Network code

Previous topic - Next topic

MrTAToad

This is various network routines I use in Spots.  The more interesting functions are sendACKResponse, processACKTimes$ and sendACKResponse%.  These deal with timers for sending (and expecting) repsonses from the server and client machines.

Code (glbasic) Select
// --------------------------------- //
// Project: Spots
// Start: Monday, November 17, 2008
// IDE Version: 6.058

// This holds the networking stuff
TYPE tNetList
isHost%
isReady%
isThisComputer% // Is this the players computer
playerID$
playerName$
timeForACK
timeForACKResponse
ENDTYPE

GLOBAL NETLENGTH_OFFSET% = 64
GLOBAL JOB_LENGTH% = 3
GLOBAL ID_LENGTH% = 3
GLOBAL ACK_BASETIME = 5000.0

FUNCTION calcNumPlaying%:value%
RETURN value%-NETLENGTH_OFFSET%
ENDFUNCTION

FUNCTION returnNumPlaying$:numPlaying%
RETURN CHR$(NETLENGTH_OFFSET%+numPlaying%)
ENDFUNCTION

FUNCTION createNumPlaying$:numPlaying%
RETURN PLAYING$+returnNumPlaying$(numPlaying%)
ENDFUNCTION

FUNCTION returnPlayerIndex$:index%
RETURN CHR$(NETLENGTH_OFFSET%+index%)
ENDFUNCTION

FUNCTION createPlayerIndex$:index%
RETURN PLAYER$+returnPlayerIndex$(index%)
ENDFUNCTION

FUNCTION returnPlayerName$:name$
RETURN CHR$(NETLENGTH_OFFSET%+LEN(name$))+name$
ENDFUNCTION

FUNCTION returnPlayerID$:playerID$
RETURN CHR$(NETLENGTH_OFFSET%+LEN(playerID$))+playerID$
ENDFUNCTION

FUNCTION createPlayerName$:name$
RETURN PLAYERNAME$+returnPlayerName$(name$)
ENDFUNCTION

FUNCTION createPlayerID$:playerID$
RETURN PLAYERID$+returnPlayerID$(playerID$)
ENDFUNCTION

FUNCTION getPlayerID$:data$
LOCAL len%
LOCAL pos%

pos%=INSTR(data$,PLAYERID$)
IF pos%<>-1
INC pos%,LEN(PLAYERID$)
len%=ASC(MID$(data$,pos%,1))-NETLENGTH_OFFSET%
INC pos%,1
RETURN MID$(data$,pos%,len%)
ENDIF

RETURN ""
ENDFUNCTION

FUNCTION getPlayerName$:data$
LOCAL len%
LOCAL pos%

pos%=INSTR(data$,PLAYERNAME$)
IF pos%<>-1
INC pos%,LEN(PLAYERNAME$)
len%=ASC(MID$(data$,pos%,1))-NETLENGTH_OFFSET%
INC pos%,1
RETURN MID$(data$,pos%,len%)
ENDIF

RETURN ""
ENDFUNCTION

// Create a string containing the number of players, each players name and the network ID string
FUNCTION getPlayersList$:numPlaying%
LOCAL temp$
LOCAL loop%

temp$=createNumPlaying$(numPlaying%)

// Get list of all players
//DEBUG "Num playing : "+numPlaying
FOR loop%=0 TO numPlaying%-1
temp$=temp$+returnPlayerIndex$(loop%)
//temp$=temp$+returnPlayerName$(_getPlayerName$(loop%))+","+_getPlayerID$(loop%))
NEXT

RETURN temp$
ENDFUNCTION

FUNCTION sendAllPlayersMessage:hostID$,numPlaying%
NETSENDMSG(hostID$,"",getPlayersList$(numPlaying%))
ENDFUNCTION

// Process networking messages
FUNCTION getNetworkMessage%:playerID$,BYREF job$,BYREF data$
LOCAL msg$
LOCAL id$

msg$=NETGETMSG$(playerID$)
IF msg$<>""
job$=MID$(msg$,0,JOB_LENGTH%)
data$=MID$(msg$,JOB_LENGTH%,LEN(msg$))

SELECT job$
CASE REQUESTFORPRESENCE$
id$=getPlayerID$(data$)
DEBUG "Request from "+id$+"\n"
IF id$<>""
sendACKResponse(playerID$,id$)
ELSE
networkDataError(playerID$,FALSE)
ENDIF
CASE COMPUTERPRESENT$
id$=getPlayerID$(data$)
DEBUG "Response received from "+id$+"\n"
IF id$<>""
// Find this player and reset time
sendACKResponse(playerID$,id$,FALSE)
ELSE
networkDataError(playerID$,FALSE)
ENDIF
DEFAULT
RETURN TRUE
ENDSELECT
ENDIF

RETURN FALSE
ENDFUNCTION

FUNCTION addPlayer:playerID$,isHost%,playerName$
LOCAL n AS tNetList

n.isHost%=isHost%
n.playerID$=playerID$
n.playerName$=playerName$
IF isHost%=TRUE
n.isReady%=TRUE
ELSE
n.isReady%=FALSE
ENDIF
n.timeForACK=ACK_BASETIME+RND(1000.0)
n.timeForACKResponse=0.0

DIMPUSH playerNetworkList[],n
ENDFUNCTION

FUNCTION doReady%:isReady%,playerID$
LOCAL n AS tNetList

FOREACH n IN playerNetworkList[]
IF n.playerID$=playerID$
n.isReady%=isReady%
RETURN TRUE
ENDIF
NEXT

RETURN FALSE
ENDFUNCTION

FUNCTION deletePlayerID%:playerID$
LOCAL n AS tNetList

FOREACH n IN playerNetworkList[]
IF n.playerID$=playerID$
DELETE n
RETURN TRUE
ENDIF
NEXT

RETURN FALSE
ENDFUNCTION

FUNCTION sendKickMessage$:index%,hostID$
NETSENDMSG(hostID$,playerNetworkList[index%].playerID$,KICKMESSAGE$)
RETURN playerNetworkList[index%].playerID$
ENDFUNCTION

// Send a disconnect message from host to all clients or from client to host
FUNCTION closeConnection:BYREF playerID$,toID$,BYREF beenAccepted%,BYREF isReady%
// Send the disconnect message and close the connection
IF playerID$<>""
NETSENDMSG(playerID$,toID$,DISCONNECT$+createPlayerID$(playerID$))
NETDESTROYPLAYER playerID$
DEBUG "Player destroyed"
deletePlayerID(playerID$)
playerID$=""
beenAccepted%=FALSE
isReady%=FALSE
ENDIF
ENDFUNCTION

FUNCTION _getPlayerName$:index%
RETURN playerNetworkList[index%].playerName$
ENDFUNCTION

FUNCTION _getPlayerID$:index%
RETURN playerNetworkList[index%].playerID$
ENDFUNCTION

FUNCTION _getIsHost%:index%
RETURN playerNetworkList[index%].isHost%
ENDFUNCTION

FUNCTION processACKTimes$:playerID$,speed
LOCAL n AS tNetList
LOCAL y%
LOCAL out$=""

out$=""
PRINT "This Computer : "+playerID$,0,0
y%=16
FOREACH n IN playerNetworkList[]
IF n.playerID$<>playerID$
PRINT "Player : "+n.playerID$+" T/ACK : "+n.timeForACK+" R/Time : "+n.timeForACKResponse,0,y%
INC y%,16
IF n.timeForACK>0.0
DEC n.timeForACK,speed
IF n.timeForACK<=0.0
DEBUG "Send ACK Request from "+playerID$+" -> "+n.playerID$+"\n"
IF NETSENDMSG(playerID$,n.playerID$,REQUESTFORPRESENCE$+createPlayerID$(playerID$))
ELSE
DEBUG "Net Send Error!\n"
ENDIF

n.timeForACKResponse=ACK_BASETIME+RND(1000.0)
ENDIF
ELSE
IF n.timeForACKResponse>0.0
DEC n.timeForACKResponse,speed
IF n.timeForACKResponse<0.0
out$=n.playerID$
ENDIF
ENDIF
ENDIF
ENDIF
NEXT

RETURN out$
ENDFUNCTION

FUNCTION sendACKResponse%:playerID$,toID$,sendMessage%=TRUE
LOCAL n AS tNetList

FOREACH n IN playerNetworkList[]
DEBUG "Looking for "+playerID$+" Found : "+n.playerID$+"\n"
IF n.playerID$=toID$
IF sendMessage%=TRUE
DEBUG "Send ACK Response from "+playerID$+" -> "+toID$+"\n"
IF NETSENDMSG(playerID$,toID$,COMPUTERPRESENT$+createPlayerID$(playerID$))
ELSE
DEBUG "Network send error\n"
ENDIF
ENDIF
n.timeForACK=ACK_BASETIME+RND(1000.0)
n.timeForACKResponse=0.0
RETURN TRUE
ENDIF
NEXT

RETURN FALSE
ENDFUNCTION


My main network processing system is :

Code (glbasic) Select
FUNCTION getNetworkMessage%:playerID$,BYREF job$,BYREF data$
LOCAL msg$
LOCAL id$

msg$=NETGETMSG$(playerID$)
IF msg$<>""
job$=MID$(msg$,0,JOB_LENGTH%)
data$=MID$(msg$,JOB_LENGTH%,LEN(msg$))

SELECT job$
CASE REQUESTFORPRESENCE$
id$=getPlayerID$(data$)
DEBUG "Request from "+id$+"\n"
IF id$<>""
sendACKResponse(playerID$,id$)
ELSE
networkDataError(playerID$,FALSE)
ENDIF
CASE COMPUTERPRESENT$
id$=getPlayerID$(data$)
DEBUG "Response received from "+id$+"\n"
IF id$<>""
// Find this player and reset time
sendACKResponse(playerID$,id$,FALSE)
ELSE
networkDataError(playerID$,FALSE)
ENDIF
DEFAULT
RETURN TRUE
ENDSELECT
ENDIF

RETURN FALSE
ENDFUNCTION

trucidare

Nice one.
i worked a half year on working classes like this in c++.
MacBook Pro 2,2 GHz Core 2 Duo, 4 GB RAM, 160 GB HDD, 8600M GT
Core i3 - 3,07 GHz, 8 GB Ram, 2.5 TB HDD, Geforce GTX 260+ OC

MrTAToad

Fortunately, no timing system is needed yet :)