Hi everyone,
I recently got back into Dark Basic after taking a long vacation with Python. I remember using Benjamin's MultiSync plugin in previous projects and I just finished downloading his latest release. This release comes with an example server and client program. Everything works great and flawlessly, except for a ground height issue I am having. Strangely enough I had this same problem back when I first started using DbPro but cannot remember my solution.
After booting up the server, I will connect with one client which I will call client A. Client A's cube is correct heightwise as long as it is on flat ground. The cube does not however change its y coordinate in response to changes in matrix height as show by the two screen shots. Now the really strange part is that if I connect a second client, which I will call client B, both clients work perfectly, their cubes scaling the hills with ease.
If I exit out of A or B, the remaining client's cube goes back to not responding to changes in matrix height. This leads me to believe that the problem is rectified through some sort of communication between clients, but I'm not sure what.
I have a pretty good understanding of networks from python (just didn't want to go through the hassle of threading to achieve asynchronous network communication).
Below are the screenshots and the code for both the server and the client. They are almost entirely Benjamin's with a few additions made by me. Those long "get ground height" in place of y values are mine. I also added in the player.y and player.realy variables and added them to the network send/receive list.
Any help is greatly appreciated.
Client:
` Constants -------------------------------------
#constant SENDGAP 0
#constant MAXIMUM_PLAYERS 10
#constant MESSAGE_ID_NAME 0
#constant MESSAGE_ID_GENERAL 1 : ` Contains just player data
#constant MESSAGE_ID_GENERALFULL 2 : ` Contains player numbers and player data
#constant MESSAGE_ID_PLAYERJOINED 3
#constant MESSAGE_ID_PLAYERQUIT 4
#constant FLAG_UP 1
#constant FLAG_DOWN 2
#constant FLAG_LEFT 4
#constant FLAG_RIGHT 8
` -----------------------------------------------
` Types ------------------------------------------
type player_data
exist as boolean
name as string
x as float
z as float
y as float
realx as float
realz as float
realy as float
angle as float
key_up as boolean
key_down as boolean
key_left as boolean
key_right as boolean
endtype
` ------------------------------------------------
` Variables --------------------------------------
global LASTSENT as integer
global NAME as string
global dim player(MAXIMUM_PLAYERS) as player_data
global lastFlags as byte
global toSend
` ------------------------------------------------
sync off
autocam off
result = net connect("localhost")
if not result
print "Could not connect: "+chr$(34)+net get error()+chr$(34)+"."
print "Press any key to exit."
wait key
end
endif
input "Name: ", NAME
net put byte MESSAGE_ID_NAME
net put string NAME
net send
make matrix 1, 1000, 1000, 10, 10
load image "media\grass.jpg", 1
prepare matrix texture 1, 1, 1, 1
fill matrix 1, 0, 1
position matrix 1, 0, 0, 0
set matrix height 1,2,2,20
set matrix height 1,5,3,30
set matrix height 1,3,6,20
set matrix height 1,7,4,20
update matrix 1
make object cube 1, 10
position object 1, object position x(1), (get ground height(1, object position x(1), object position z(1)) + 5), object position z(1)
rem load mesh "media\person.x", 1
rem make object 1, 1, 0
rem position object 1, object position x(1), (get ground height(1, object position x(1), object position z(1)) + 6), object position z(1)
make object cube 40, 10
ghost object on 40
hide object 40
sync on
sync rate 60
do
HandleControls()
HandleCamera()
if net connected()
HandleNetwork()
else
CenterBox(screen width()/2, screen height()/2, 200, 26, "WE'VE LOST THE SERVER!")
endif
HandleMovement()
sync
loop
function HandleMovement()
for x = 1 to MAXIMUM_PLAYERS
if player(x).exist
rem real values are the actual current values
if player(x).key_up
player(x).realx = player(x).realx + sin(player(x).angle)
player(x).realz = player(x).realz + cos(player(x).angle)
endif
if player(x).key_down
player(x).realx = player(x).realx - sin(player(x).angle)
player(x).realz = player(x).realz - cos(player(x).angle)
endif
if player(x).key_left then player(x).angle = wrapvalue(player(x).angle-1)
if player(x).key_right then player(x).angle = wrapvalue(player(x).angle+1)
distx# = abs(player(x).realx-player(x).x)
speedx# = distx# / 10.0
distz# = abs(player(x).realz-player(x).z)
speedz# = distz# / 10.0
angle# = atanfull(player(x).realx-player(x).x, player(x).realz-player(x).z)
player(x).x = player(x).x + (sin(angle#)*speedx#)
player(x).z = player(x).z + (cos(angle#)*speedz#)
player(x).y = (get ground height(1, player(x).x, player(x).z) + 5)
yrotate object x+10, player(x).angle
position object x+10, player(x).x, player(x).y, player(x).z
position object 1, object position x(1), (get ground height(1, object position x(1), object position z(1)) + 5), object position z(1)
center text object screen x(x+10), object screen y(x+10)-13, player(x).name
endif
next x
endfunction
function HandleNetwork()
while net get message()
inc MSGSRECVD
select net get byte()
case MESSAGE_ID_GENERAL
playerNum = net get byte()
player(playerNum).realx = net get float()
player(playerNum).realz = net get float()
player(playerNum).realy = net get float()
player(playerNum).angle = net get byte() * 1.411
ApplyFlags(playerNum, net get byte())
endcase
case MESSAGE_ID_GENERALFULL
while net get message remainder() > 0
playerNum = net get byte()
player(playerNum).exist = 1
player(playerNum).name = net get string()
player(playerNum).realx = net get float()
player(playerNum).realz = net get float()
player(playerNum).realy = net get float()
player(playerNum).angle = net get byte() * 1.411
ApplyFlags(playerNum, net get byte())
make object cube playerNum+10, 10
ApplyPosition(playerNum)
endwhile
endcase
case MESSAGE_ID_PLAYERJOINED
playerNum = net get byte()
player(playerNum).exist = 1
player(playerNum).name = net get string()
make object cube playerNum+10, 10
endcase
case MESSAGE_ID_PLAYERQUIT:
ResetPlayer(net get byte())
endcase
endselect
endwhile
if toSend and LASTSENT+SENDGAP<timer()
net put byte MESSAGE_ID_GENERAL
net put float object position x(1)
net put float object position z(1)
net put float get ground height(1, object position x(1), object position z(1))
net put byte (object angle y(1) / 1.411)
flags = (upkey() || downkey() << 1 || leftkey() << 2 || rightkey() << 3)
net put byte flags
net send
toSend = 0
endif
endfunction
function HandleControls()
flags = 0
if upkey() then move object 1, 1 : flags = flags || FLAG_UP
if downkey() then move object 1, -1 : flags = flags || FLAG_DOWN
if leftkey() then yrotate object 1, wrapvalue(object angle y(1)-1) : flags = flags || FLAG_LEFT
if rightkey() then yrotate object 1, wrapvalue(object angle y(1)+1) : flags = flags || FLAG_RIGHT
if flags <> lastFlags
toSend = 1
lastFlags = flags
LASTSENT = timer()
endif
endfunction
function HandleCamera()
xPos# = object position x(1) + cos(270-object angle y(1)) * 50
zPos# = object position z(1) + sin(270-object angle y(1)) * 50
position camera xPos#, 40, zPos#
point camera object position x(1), get ground height(1, object position x(1), object position z(1)) + 5, object position z(1)
endfunction
function ResetPlayer(playerNum as integer)
if object exist(playerNum+10) then delete object playerNum+10
player(playerNum).exist = 0
player(playerNum).name = ""
player(playerNum).x = 0
player(playerNum).z = 0
player(playerNum).y = 0
player(playerNum).angle = 0
player(playerNum).key_up = 0
player(playerNum).key_down = 0
player(playerNum).key_left = 0
player(playerNum).key_right = 0
endfunction
function ApplyFlags(playerNum as integer, flags as integer)
if flags && FLAG_UP
player(playerNum).key_up = 1
else
player(playerNum).key_up = 0
endif
if flags && FLAG_DOWN
player(playerNum).key_down = 1
else
player(playerNum).key_down = 0
endif
if flags && FLAG_LEFT
player(playerNum).key_left = 1
else
player(playerNum).key_left = 0
endif
if flags && FLAG_RIGHT
player(playerNum).key_right = 1
else
player(playerNum).key_right = 0
endif
endfunction
function ApplyPosition(playerNum as integer)
position object playerNum+10, object position x(1), (get ground height(1, object position x(1), object position z(1)) + 5), object position z(1)
yrotate object playerNum+10, player(playerNum).angle
endfunction
function CenterBox(x as integer, y as integer, xSize as integer, ySize as integer, textString as string)
xPos = x-(xSize/2)
yPos = y-(ySize/2)
ink rgb(200, 200, 200), 0
box xPos, yPos, xPos+xSize, yPos+ySize
ink rgb(255, 255, 255), 0
center text x, y-(text height("A")/2), textString
endfunction
Server:
` Constants --------------------------------------
#constant MAXIMUM_PLAYERS 10
#constant MESSAGE_ID_NAME 0
#constant MESSAGE_ID_GENERAL 1 : ` Contains just player data
#constant MESSAGE_ID_GENERALFULL 2 : ` Contains player numbers and player data
#constant MESSAGE_ID_PLAYERJOINED 3
#constant MESSAGE_ID_PLAYERQUIT 4
#constant FLAG_UP 1
#constant FLAG_DOWN 2
#constant FLAG_LEFT 4
#constant FLAG_RIGHT 8
` ------------------------------------------------
` Types ------------------------------------------
type player_data
exist as boolean
active as boolean
name as string
x as float
z as float
y as float
realx as float
realz as float
realy as float
angle as float
key_up as boolean
key_down as boolean
key_left as boolean
key_right as boolean
endtype
` ------------------------------------------------
` Variables --------------------------------------
global dim player(MAXIMUM_PLAYERS) as player_data
global MOUSE_LBM_PRESSED as boolean
` ------------------------------------------------
sync off
autocam off
result = net host(MAXIMUM_PLAYERS)
if not result
print "Could not start server: "+chr$(34)+net get error()+chr$(34)+"."
print "Press any key to exit."
wait key
end
endif
make matrix 1, 1000, 1000, 10, 10
position camera 500, 1000, 500
point camera 500, 0, 500
sync on
sync rate 60
do
text 0, 0, str$(screen fps())
text 0, 13, "There are "+str$(net get player amount())+" players connected."
if spacekey() then net kick 1
HandleNetwork()
HandleMouseOvers()
HandleMovement()
sync
loop
function HandleMovement()
for x = 1 to MAXIMUM_PLAYERS
if player(x).exist
if player(x).key_up
player(x).realx = player(x).realx + sin(player(x).angle)
player(x).realz = player(x).realz + cos(player(x).angle)
endif
if player(x).key_down
player(x).realx = player(x).realx - sin(player(x).angle)
player(x).realz = player(x).realz - cos(player(x).angle)
endif
if player(x).key_left then player(x).angle = wrapvalue(player(x).angle-1)
if player(x).key_right then player(x).angle = wrapvalue(player(x).angle+1)
distx# = abs(player(x).realx-player(x).x)
speedx# = distx# / 10.0
distz# = abs(player(x).realz-player(x).z)
speedz# = distz# / 10.0
angle# = atanfull(player(x).realx-player(x).x, player(x).realz-player(x).z)
player(x).x = player(x).x + (sin(angle#)*speedx#)
player(x).z = player(x).z + (cos(angle#)*speedz#)
player(x).y = (get ground height(1, player(x).x, player(x).z) + 5)
yrotate object x+10, player(x).angle
position object x+10, player(x).x, player(x).y, player(x).z
endif
next x
endfunction
function HandleMouseOvers()
result = pick object(mousex(), mousey(), 10, 30)
if result = 0 then exitfunction
if result > 9 and result < 20
text mousex(), mousey()-13, player(result-10).name
endif
endfunction
function HandleNetwork()
` Player joining ------------
` ---------------------------
result = net player joined()
while result > 0
make object cube 10+result, 10
player(result).exist = 1
rem send states & positions of players
net put byte MESSAGE_ID_GENERALFULL
for x = 1 to MAXIMUM_PLAYERS
if net player connected(x)
if player(x).active
net put byte x
net put string player(x).name
net put float player(x).realx
net put float player(x).realz
net put float player(x).realy
net put byte player(x).angle / 1.411
net put byte GetFlags(x)
endif
endif
next x
net send result
result = net player joined()
endwhile
` Player leaving -------------
` ----------------------------
result = net player left()
while result > 0
ResetPlayer(result)
net put byte MESSAGE_ID_PLAYERQUIT
net put byte result
net send all
result = net player left()
endwhile
` Message processing ---------
` ----------------------------
while net get message()
playerNum = net message from()
select net get byte()
case MESSAGE_ID_NAME
playerNum = net message from()
player(playerNum).name = net get string()
player(playerNum).active = 1
color object playerNum+10, rgb(0, 255, 0)
` Notify other players
net put byte MESSAGE_ID_PLAYERJOINED
net put byte playerNum
net put string player(playerNum).name
for x = 1 to MAXIMUM_PLAYERS
if net player connected(x)
if x <> playerNum
net send x, 1
endif
endif
next x
` Clear message data
net send 0
endcase
case MESSAGE_ID_GENERAL
player(playerNum).realx = net get float()
player(playerNum).realz = net get float()
player(playerNum).realy = net get float()
player(playerNum).angle = net get byte() * 1.411
ApplyFlags(playerNum, net get byte())
ApplyPosition(playerNum)
` Forward message on
net put byte MESSAGE_ID_GENERAL
net put byte playerNum
net put float player(playerNum).realx
net put float player(playerNum).realz
net put float player(playerNum).realy
net put byte player(playerNum).angle / 1.411
net put byte GetFlags(playerNum)
SendAllExcept(playerNum)
endcase
endselect
endwhile
endfunction
function ResetPlayer(playerNum as integer)
if object exist(playerNum+10) then delete object playerNum+10
player(playerNum).exist = 0
player(playerNum).active = 0
player(playerNum).name = ""
player(playerNum).x = 0
player(playerNum).z = 0
player(playerNum).y = 0
player(playerNum).realx = 0
player(playerNum).realz = 0
player(plyaerNum).realy = 0
player(playerNum).angle = 0
player(playerNum).key_up = 0
player(playerNum).key_down = 0
player(playerNum).key_left = 0
player(playerNum).key_right = 0
endfunction
function SendAllExcept(except as integer)
for x = 1 to MAXIMUM_PLAYERS
if net player connected(x)
if x <> except
net send x, 1
endif
endif
next x
net send 0
endfunction
function GetFlags(playerNum as integer)
local states as byte
if player(playerNum).key_up then states = states || FLAG_UP
if player(playerNum).key_down then states = states|| FLAG_DOWN
if player(playerNum).key_left then states = states || FLAG_LEFT
if player(playerNum).key_right then states = states || FLAG_RIGHT
endfunction states
function ApplyFlags(playerNum as integer, flags as integer)
if flags && FLAG_UP
player(playerNum).key_up = 1
else
player(playerNum).key_up = 0
endif
if flags && FLAG_DOWN
player(playerNum).key_down = 1
else
player(playerNum).key_down = 0
endif
if flags && FLAG_LEFT
player(playerNum).key_left = 1
else
player(playerNum).key_left = 0
endif
if flags && FLAG_RIGHT
player(playerNum).key_right = 1
else
player(playerNum).key_right = 0
endif
endfunction
function ApplyPosition(playerNum as integer)
position object playerNum+10, player(playerNum).x, player(playerNum).y, player(playerNum).z
yrotate object playerNum+10, player(playerNum).angle
endfunction