Posted: 16th Jun 2007 20:43
Hi all.

Here is the thing. I'm trying to learn multiplayer. The game I'm doing is simply a normal deathmatch among a number of cubes and an deadly ground (touch it and you loose health). Anyway, there are some buggs in it that I have no idea about how to fix (to 'debug' the game I run it on my two computers at home).

I'm using tempest for the multiplayer and sparkys collision plugin for the collision.

The first one is that the objects don't turn around on the other computer when I play. They just face the same direction all the time. Even when I look around on the spot, you can't se any rotation on the other computer.

The second bug is that you cant kill your enemy. I cant figure out why. It should work, but doesn't. But I think the error is in either the subrutine that recive multiplayer data ('recive'), the one where the weapon is controlled ('player') or it's in the subrutine that sends multiplayer data ('send').

Anyway, here is the source:
+ Code Snippet
set display mode 1024, 768, 32
randomize timer()
autocam off
hide mouse

rem The UDT's
type _data_
  dead as byte
  hidden as boolean
endtype

type _mes_
  mess as string
  sender as string
endtype

rem Globals
global sw as word
global sh as word

sw = screen width() / 2
sh = screen height() / 2

rem Define variables
health as integer
jumpTime as dword
chatTime as dword
deadTime as dword
dead as byte
dam as byte
res as boolean
chating as boolean

rem The arrays
dim death( 11 ) as _data_

InitMessages()

rem Loop
do

rem Clear screen
cls

rem Choose
print "Boxes!"
print "1) Host"
print "2) Join"
print "3) End program"
input "Choise: ", choise$

if choise$ = "1"

  rem Host a game
  input "Name: ", name$
  input "Game name: ", gaName$
  res = THost("0.0.0.0", 10, name$)

  if res = 1

    rem If you could host...
    TRegisterGame gaName$, "Deathmatch", "Boxing cylinders", 3600000
    exit

  else

    rem Else, display an error message.
    print "ERROR: Could not set up an server."
    wait key

  endif

else

  if choise$ = "2"

    rem Connect to a server
    input "Name: ", name$
    res = TJoin("5.177.135.53", name$)

    if res = 1

      rem If the connection was succesfull
      exit

    else

      rem If not...
      print "ERROR: Could not connect."
      wait key

    endif

  else

    if choise$ = "3"
      end
    endif

    rem If you chose an invalid option
    print "ERROR: Invalid option."
    wait key

  endif

endif

loop

sync on : sync rate 75

rem Setup the ground
ground = GetNewObjectNumber( 789 )
make object box ground, 10000, 150, 10000
position object ground, -207, -75, -207
color object ground, rgb(255, 0, 0)
SC_SetupObject ground, 1, 2
SC_UpdateObject ground

rem Fill the world
for n = 1 to 6
  for m = 1 to 6
    obj = GetNewObjectNumber( 790 )
    height = 180 + 180 * sin((n ^ 2) * (m ^ 2))
    make object box obj, 120, height, 87 * (m + n * sin( n ))
    position object obj, n * 442, height, m * (389 + 17 * n)
    color object obj, rgb(0, 255, 0)
    SC_SetupObject obj, 1, 2
    SC_UpdateObject obj
  next m
next n
for n = 1 to 5
  for m = 1 to 5
    obj = GetNewObjectNumber( 790 )
    make object box obj, 169, 10 + 8 * m * n, 350
    position object obj, n * 711 + 378 * sin(n * m + 23 * n + cos(45 * m) + atan(1 / (n + m))), 60 * cos( tan((m / n) / 0.637) ) + (10 * n) / m + 54, m * 622 + n * 67
    color object obj, rgb(0, 255, 0)
    SC_SetupObject obj, 1, 2
    SC_UpdateObject obj
  next m
next n
for n = 1 to 4
  for m = 1 to 4
    obj = GetNewObjectNumber( 790 )
    make object box obj, 220, 20, 550
    position object obj, n * 771, 107 + 50 * n * m, m * 1089
    color object obj, rgb(0, 255, 0)
    SC_SetupObject obj, 1, 2
    SC_UpdateObject obj
  next m
next n

you = TGetThisID()

rem Create the player
make object cube you, 20
position object you, rnd( 2000 ) + 111, 430, rnd( 2000 ) + 111
color object you, rgb(255, 205, 55)
SC_SetupObject you, 1, 2
SC_UpdateObject you

rem Player properties
health = 100

repeat

  rem The subrutines
  gosub recive
  gosub disconnect
  gosub hud
  if chating = 1 then gosub chat
  gosub player
  gosub gravity
  gosub collision
  gosub updateGrav
  gosub jumping
  gosub camera
  gosub send

  msge$ = ""
  target = 0
  prevY# = object position y( you )
  sync

until keystate( 88 ) = 1

rem Disconnect if connected
if TConnected()
  TDisconnect
endif

end

recive:

rem Recive data, if it exist
while TGetMessage()
  id = id + 1
  sender = TGetSender()
  x# = TGetFloat()
  y# = TGetFloat()
  z# = TGetFloat()
  ay# = TGetFloat()
  death( sender ).dead = TGetByte()
  dam = TGetByte()
  mess$ = TGetString()
  if mess$ <> " " and mess$ <> "  " and mess$ <> "   " then AddMessage(TGetPlayerName( sender ) + ": ", mess$)
  if dam = you
    health = health - 37
  endif

  if object exist( sender )

    if death( sender ).dead = 0

      if death( sender ).hidden = 1
        show object sender
        death( sender ).hidden = 0
      endif

      position object sender, x#, y#, z#
      yrotate object sender, y#
      if object in screen( sender )
        center text object screen x( sender ), object screen y( sender ), TGetPlayerName( sender )
      endif
    else

      if death( sender ).hidden = 0
        hide object sender
        death( sender ).hidden = 1
      endif
    endif
  else
    rem If the object does not exist, create it. And then angle it corrctly.
    if death( sender ).dead = 0
      make object cube sender, 20
      position object sender, x#, y#, z#
      yrotate object sender, ay#
      color object sender, rgb(255, 205, 55)
      SC_SetupObject sender, 1, 2
      SC_UpdateObject sender
    endif
  endif
endwhile
id = 0

return

disconnect:

for n = 1 to 10
  if not TPlayerExist( n )
    if object exist( n )
      SC_RemoveObject n
      delete object n
    endif
  endif
next n

return

hud:

rem Display
text 1, 1, "FPS: " + str$( screen fps() )
text 1, 18, "Health: " + str$( health )
text 1, 35, "Grav: " + str$( grav# )
if health > 0 then circle sw, sh, 3

rem Show the other chat-messages
for n = 0 to 6
  text 1, 52 + 17 * (n + 1), messages( n ).sender + messages( n ).mess
next n

return

chat:

rem Write message
if keystate( 14 ) = 0
  if entry$() <> "" and (timer() - chatTime) / 25 > 0
    message$ = message$ + entry$()
    chatTime = timer()
  endif
else
  if (timer() - chatTime) / 47 > 0
    message$ = left$(message$, len( message$ ) - 1)
    chatTime = timer()
  endif
endif

rem Send message
if returnkey() = 1
  chating = 0
  msge$ = message$
  message$ = ""
  if msge$ <> "" and msge$ <> " " and msge$ <> "  "
    AddMessage("(You) " + name$ + ": ", msge$)
  endif
endif

rem Display the message
text 1, 52, "Say: " + message$

rem Clear the entry buffer
clear entry buffer

return

player:

rem Dead or not?
if health < 1
  if dead = 0
    dead = 1
    deadTime = timer()
    color light 0, rgb(255, 0, 0)
  else
    center text sw, sh - text height( "Tp" ) / 2, "Time to respawn: " + str$(5 - (timer() - deadTime) / 1000)
  endif
endif

rem Respawn
if dead = 1 and (timer() - deadTime) / 1000 > 4
  dead = 0
  health = 100
  color light 0, rgb(255, 255, 255)
  position object you, rnd( 2200 ) - 1100, 430, rnd( 2200 ) - 1100
endif

rem Store the position of the player
ox# = object position x( you )
oy# = object position y( you )
oz# = object position z( you )

if chating = 0 and dead = 0
  rem Move object
  move object you, 7 * keystate( 17 ) - 4 * keystate( 31 )
  zrotate object you, 0
  move object left you, 5 * keystate( 30 ) - 5 * keystate( 32 )

  rem Start to chat
  if keystate( 21 ) = 1
    chating = 1
    clear entry buffer
  endif
endif

rem Using the weapon
if mouseclick() = 1 and dead = 0
  obj = pick object(sw, sh, 1, you - 1)
  if obj = 0 then obj = pick object(sw, sh, you + 1, 10)
  if not obj = 0
    target = obj
  endif
endif

nx# = object position x( you )
nz# = object position z( you )

rem The angles
yrotate object you, object angle y( you ) + mousemovex() / 2
xrotate camera camera angle x() + mousemovey() / 2
if camera angle x() > 90
  xrotate camera 90
else
  if camera angle x() < -90 then xrotate camera -90
endif

return

gravity:

if dead = 0 then position object you, object position x( you ), object position y( you ) + grav#, object position z( you )
ny# = object position y( you )

if object collision(you, ground) = 1 then health = health - 3
if ny# < -100 then health = -78

return

collision:

rem Check collision
collide = SC_SphereSlideGroup(1, ox#, oy#, oz#, nx#, ny#, nz#, 19, 0)

if collide > 0

  rem Perform sliding collision
  newX# = SC_GetCollisionSlideX()
  newY# = SC_GetCollisionSlideY()
  newZ# = SC_GetCollisionSlideZ()

  rem Position the player at the new position
  position object you, newX#, newY#, newZ#

endif

rem Update the player
SC_UpdateObject you

return

updateGrav:

if prevY# - object position y( you ) <> 0 and grav# > -11 and dead = 0
  grav# = grav# - 0.16
  if grav# < -11 then grav# = -11
endif

return

jumping:

if abs(prevY# - object position y( you )) = 0 and chating = 0 and dead = 0
  if spacekey() = 1 and (timer() - jumpTime) / 500 > 1
    grav# = 11
    jumpTime = timer()
  endif
endif

return

camera:

rem Position and rotate the camera
youx# = object position x( you )
youy# = object position y( you )
youz# = object position z( you )
youa# = object angle y( you )
position camera youx#, youy#, youz#
yrotate camera youa#

return

send:

rem Send data
TPutFloat youx#
TPutFloat youy#
TPutFloat youz#
TPutFloat youa#
TPutByte dead
TPutByte target
TPutString msge$ + " "
TSendAll

TSync

return



function GetNewObjectNumber(start as word)

newObj = start
repeat

  newObj = newObj + 1

until not object exist( newObj )

endfunction newObj



function InitMessages()

dim messages( 6 ) as _mes_

endfunction



function AddMessage(sender as string, anmessage as string)

down1S as string
down1M as string
down2S as string
down2M as string

down1S = messages( 0 ).sender
down1M = messages( 0 ).mess

messages( 0 ).sender = sender
messages( 0 ).mess = anmessage

down2S = messages( 1 ).sender
down2M = messages( 1 ).mess
messages( 1 ).sender = down1S
messages( 1 ).mess = down1M

down1S = messages( 2 ).sender
down1M = messages( 2 ).mess
messages( 2 ).sender = down2S
messages( 2 ).mess = down2M

down2S = messages( 3 ).sender
down2M = messages( 3 ).mess
messages( 3 ).sender = down1S
messages( 3 ).mess = down1M

down1S = messages( 4 ).sender
down1M = messages( 4 ).mess
messages( 4 ).sender = down2S
messages( 4 ).mess = down2M

down2S = messages( 5 ).sender
down2M = messages( 5 ).mess
messages( 5 ).sender = down1S
messages( 5 ).mess = down1M
messages( 6 ).sender = down2S
messages( 6 ).mess = down2M

endfunction

delete memblock 1


Can someone please help me? Why won't the objects (that reprasent the players) rotate and why can't the players hurt each other? If you can see what's wrong, please post.
Posted: 17th Jun 2007 3:04
I can't really set that up, sorry. I looked at your code, and I think your problem with thee rotation is here, you will not believe this, but if it is your error, its only 1 letter!

if object exist( sender )

if death( sender ).dead = 0

if death( sender ).hidden = 1
show object sender
death( sender ).hidden = 0
endif

position object sender, x#, y#, z#
yrotate object sender, y# should be ay#
if object in screen( sender )
center text object screen x( sender ), object screen y( sender ), TGetPlayerName( sender )
endif
else

if death( sender ).hidden = 0
hide object sender
death( sender ).hidden = 1
endif
endif
else
rem If the object does not exist, create it. And then angle it corrctly.
if death( sender ).dead = 0
make object cube sender, 20
position object sender, x#, y#, z#
yrotate object sender, ay#
color object sender, rgb(255, 205, 55)
SC_SetupObject sender, 1, 2
SC_UpdateObject sender
endif
endif
Posted: 17th Jun 2007 13:40
One letter? LOL! Thanks, it works now .

Anyway, I also fixed the problem with not being able to hurt the opponent, so now I got both problems fixed.

But there are some more questions I have. I'm currently using tempest. Would it be better if I changed to multisync? At the moment the main reason I use tempest is that I know that you can connect without having to know the ip with it (I haven't figured out how yet, though, but it's just a matter of time). Is there a way to do this with multisync?
Posted: 17th Jun 2007 23:43
I have not started with Tempest, but looking at your code, Multisync presents pretty much the same type of interface as you are exposing to Tempest, but it uses TCP which is more reliable, but limiting in its own ways, too. (TCP, not Multisync.)

The best plan (imo) is one that already knows that both TCP and UDP are necessary to present the type of distributed application we all seem to be wanting to create.

With that in mind, why not try this:

Use Multisync to gather the players together. TCP is a reliable connection, and in fact...it will be very stubborn about not doing anything else when you create a TCP server. Its called blocking, and it is used to establish an entry point in a reliable way, so its a good thing, just a little hard to tolerate in DBPro without a plug-in. It is that way because Unix and Linux, etc. are multi-threaded OSes, so it makes that work well for many users connecting, maybe almost simultaneously. (i.e. threads)

TCP can get bogged down owing to its stubborn reliability, and also the number of TCP services (protocols) is huge, it was first.
Using TCP, you can establish a UDP multi-cast group and then Tempest is looking really good in that respect. I have not been in the market to do much more than what I did last week about how to publish and get the key ingredient in this, which is the IP of the TCP server I am talking about now.

If you do not have a domain name or some other ability to run the server, then game assets need to be distributed another way. ftp is the best way to do this, but that requires a host, too.

Most ISPs are quite clear about running servers, they say this about it: don't.

If you start serving up multi-megabyte files using ftp (assuming you will be able to, that is.), and then there are tons of packets arriving and going out TCP ports, you might exceed your bandwidth, so...this is a delicate matter, how to do it without violating the agreement, and still have a substantial game?

I watch the way XBoxLive works for Halo, for example. There are kids hosting Halo games, and others playing, Microsoft is only putting them together, and the bulk of the data is naturally on my Halo CD, so the only stuff that needs transmitted is the player info.

DirectPlay seems to be able to do this, but it requires the ability to establish the multi-cast group, and manage that. That is not usually what most networked games look like when you start them out, they look like peer-to-peer apps, and I am talking about a server that exists only to set this up, after that...it is peer-to-peer....the multi-cast group is the game.

In the end, it will take using a little bit of all of it, after all, these are Windows machines and what we want is more suited to Linux as far as the server is concerned. I would even say that a good Linux programmer could do it using Linux alone! Its not impossible, I think it is just a very long journey.
Posted: 18th Jun 2007 0:00
I'd be a little leery about calling it "multicast". The vast majority of ISPs actively block multicast traffic. They somehow think it's going to use up their bandwidth. Frankly I don't understand it because multicast is designed to use less bandwidth, not more.
Posted: 18th Jun 2007 1:26
Agreed, as I was much more than leary to label it that myself. All very valid, as we have discovered over the last few months in these threads.

The best situation is being able to run services on a machine that you own, that has a static IP at least. Locally here, there is an option that appeals to me: server co-location. The ISP will host your DNS, and you provide a machine at their location with your bit of Internet real estate on it. I do not know what the cost is now, but when they first started doing it, it was in the low-to-mid price range, no more than $200/month. That is a very attractive bit of real estate for more than simply serving games.
Posted: 18th Jun 2007 14:19
So you recommend me to use both plugins? Multisync to connect to the server and everything, and then tempest for the in-game thing? Could anyone give an example about how that can be done? Because I've just started with muliplayer and don't have any clue about how to combine them.
Posted: 18th Jun 2007 14:24
I am recommending that you use TCP and UDP. I will download Tempest and see if I can get you started, I already have Multisync, so I will try to meet you in the middle, okay?
Posted: 18th Jun 2007 17:22
The best situation is being able to run services on a machine that you own, that has a static IP at least. Locally here, there is an option that appeals to me: server co-location. The ISP will host your DNS, and you provide a machine at their location with your bit of Internet real estate on it. I do not know what the cost is now, but when they first started doing it, it was in the low-to-mid price range, no more than $200/month. That is a very attractive bit of real estate for more than simply serving games.


Bandwidth with a dedicated server is something you should consider too... many of the companies I have priced for a dedicated server have two different prices for metered and unmetered bandwidth. If you end up with a popular and data intensive game, unmetered bandwidth can cost you $1300.00 USD per month.
Posted: 18th Jun 2007 18:13
That sounds ok for me. At the game I'm working on (deathmatch style), I will need to make an decent multiplayer system, so I would be very grateful for any help.
Posted: 19th Jun 2007 2:13
@Burnman - Yeah, that hit me when I pressed 'Post Message', but still, you can see I checked it last about 6 years ago! I think that, watching XBoxLive, the server doesn't eat alot of bandwidth, but each client gets alot coming at them. That is, I think, part of the key to making this work anyway, distributing the bandwidth with heavy bias on the client's receive as opposed to the host bearing the responsibility.

Mr X...okay, then. I certainly am willing to work on this as long as you'd like, and I am able. It helps me, too. I have what you see here, and that is it. I don't have the benefit of a LAN, but that seems to be more hinderance than help. I am usually the first guy killed, but if I find a pistol and a high spot, watch out!
Posted: 19th Jun 2007 13:24
Thanks jinzai. But there is just one thing. I wasn't asking for for anything more then an example of how it can be done. Help is what I need, not someone to make everything for me. I'm fully capable of doing it all in tempest, it's how to combine multysync and tempest that I'm interested in.

However, the server part is nothing I think of right now. And a dedicated server is out of the question at the moment due to a not too good economy (can't afford $200 per mounth, so $1300...).
Posted: 19th Jun 2007 17:00
I was not intending to to write everything for you; I don't have that kind of time and I'm not that magnanimous in the first place
I merely mentioned the best scenario because if you have any intent of spending alot of effort on the thing, you will likely want to present it with the best chance for success.

As far as I know, noone has done that. I did not exactly try to hunt for it, either. Its what I am doing, I don't have an example of it because I just now installed Tempest.

Now that I see you also have Sparky's collision dll which I also do not have, I can't really use your source to even attempt to do that, I need to use what I already have done using Multisync, so I guess I can't help you after all. Sorry.
Posted: 19th Jun 2007 21:45
Well, I never really was in an real need of any help when it comes to that. Was just curius abot how to combine tempest and multisync. Anyway, I'll do it with tempest.

I was not intending to to write everything for you


I'm actually glad to read that.
Posted: 20th Jun 2007 2:01
Given the fact that I took the time to answer your thread at all, and the fact that I fixed your problem, I 'd say that was out of line.

Good luck with your project, however.
Posted: 20th Jun 2007 12:23
Thanks. And thanks for the help to. Appriciate it.