Netzwerk: Spielserver im LAN suchen und anmelden
Verfasst: 26.04.2005 08:38
Also, ich versuche mich gerade in Sachen Netzwerk. Dazu habe ich ein paar der Beispielcodes aus dem CodeArchiv durchforstet und etwas zusammengebaut, das alle Computer im LAN sucht und dort nach Spielservern sucht.
Es gibt dem Spieler die Auswahlliste zurück, welche Spiele im LAN angeboten werden. Der Spieler kann sich eins aussuchen und wird am dortigen Server angemeldet.
Client-Code:
und hier ist der Code für den Server:
Ich hoffe ich habe keine Fehler mehr drin.
Zu guter letzt noch ne Verständnisfrage: Wenn ich das ganze übers Internet spielen will, müsste ich nur die IP-ADresse und den Port für den Server beim Client eingeben (und dafür die Suche weglassen) - Stimmt das?
Es gibt dem Spieler die Auswahlliste zurück, welche Spiele im LAN angeboten werden. Der Spieler kann sich eins aussuchen und wird am dortigen Server angemeldet.
Client-Code:
Code: Alles auswählen
; Konstanten
#MAX_PREFERRED_LENGTH = -1
#SV_TYPE_ALL = $FFFFFFFF
#NERR_SUCCESS = 0
#ERROR_MORE_DATA = 234
#MainWindow = 100
#MMTB = 200
;- Window Constants
Enumeration
#WND_Join_Game
EndEnumeration
;- Gadget Constants
Enumeration
#WND_Join_Game_LICON
#WND_Join_Game_BTN_OK
#WND_Join_Game_BTN_Abbruch
EndEnumeration
; Strukturen und Vars
Structure HOSTENT
h_name.l
h_aliases.l
h_addrtype.w
h_length.w
h_addr_list.l
EndStructure
Structure SERVER_INFO_101
dwPlatformId.l
lpszServerName.l
dwVersionMajor.l
dwVersionMinor.l
dwType.l
lpszComment.l
EndStructure
Structure LAN_RESULT
Name.s
IP_Name.s
Aktiv_Server.l ; 1, wenn dort ein aktiver Server gefunden werden konnte, dann sind auch die weiteren Daten belegt
Spiel_Name.s
Spieler_bisher.l
EndStructure
NewList LAN_Client.LAN_RESULT()
; Initialisieren
If InitSprite() And InitKeyboard() And InitNetwork() = 0
MessageRequester("Error", "Cant initialize Core")
End
EndIf
; Proceduren
Procedure.s GetIPbyName (NameIP.s)
TheIPAdress.s
pHostinfo = gethostbyname_(NameIP)
If pHostinfo = 0
TheIPAdress = "Unable to resolve domain name"
Else
CopyMemory (pHostinfo, hostinfo.HOSTENT, SizeOf(HOSTENT))
If hostinfo\h_addrtype <> #AF_INET
MessageRequester("Info","A non-IP address was returned",0)
Else
While PeekL(hostinfo\h_addr_list+AdressNumber*4)
ipAddress = PeekL(hostinfo\h_addr_list+AdressNumber*4)
TheIPAdress = StrU(PeekB(ipAddress),0)+"."+StrU(PeekB(ipAddress+1),0)+"."+StrU(PeekB(ipAddress+2),0)+"."+StrU(PeekB(ipAddress+3),0)
AdressNumber+1
Wend
EndIf
EndIf
ProcedureReturn TheIPAdress
EndProcedure
Procedure GetLANList()
IPResult.s
se101.SERVER_INFO_101
nStructSize = SizeOf(SERVER_INFO_101)
RetCode = NetServerEnum_(0, 101, @bufptr, #MAX_PREFERRED_LENGTH, @dwEntriesread, @dwTotalentries, #SV_TYPE_ALL, 0, @dwResumehandle)
If RetCode = #NERR_SUCCESS And RetCode <> #ERROR_MORE_DATA
For i = 0 To dwEntriesread - 1
CopyMemory( bufptr + (nStructSize * i),@se101, nStructSize)
Buffer.s=Space(512)
result=WideCharToMultiByte_(#CP_ACP, 0, se101\lpszServerName, 255, @Buffer.s, 512, 0, 0)
IPResult = GetIPbyName (Buffer)
AddElement(LAN_Client())
LAN_Client()\Name = Buffer
LAN_Client()\IP_Name = IPResult
Next
Else
MessageRequester("Info","Failed",0)
EndIf
NetApiBufferFree_(bufptr)
; SendMessage_(MMTextBox,$00B6,0,30)
EndProcedure
Procedure.l Open_WND_Join_Game()
; wählt ein Spiel aus und schliesst die offenen Verbindungen zu anderen Spielservern
; Gibt den Listindex des gewählten Lan-Spiels zurück, oder -1, wenn keines gewählt wurde
back.l = -1
If OpenWindow(#WND_Join_Game, 216, 0, 313, 399, #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar , "Join Game")
If CreateGadgetList(WindowID())
;-
ListIconGadget(#WND_Join_Game_LICON, 10, 30, 290, 330, "Spiel Name", 200)
AddGadgetColumn(#WND_Join_Game_LICON, 2, "Spieler bisher", 85)
AddGadgetColumn(#WND_Join_Game_LICON, 3, "", 1)
ButtonGadget(#WND_Join_Game_BTN_OK, 230, 370, 70, 20, "OK")
ButtonGadget(#WND_Join_Game_BTN_Abbruch, 10, 370, 70, 20, "Abbruch")
; die Gadgets vorbereiten
ResetList(LAN_Client())
While NextElement(LAN_Client())
If LAN_Client()\Aktiv_Server
AddGadgetItem(#WND_Join_Game_LICON, -1, LAN_Client()\Name + " - " + LAN_Client()\Spiel_Name + Chr(10) + Str(LAN_Client()\Spieler_bisher) + Chr(10) + Str(ListIndex(LAN_Client())))
EndIf
Wend
; Aktionsschleife
Repeat
Event = WaitWindowEvent()
If Event = #PB_EventGadget
GadgetID = EventGadgetID()
If GadgetID = #WND_Join_Game_LICON
back = Val(GetGadgetItemText(#WND_Join_Game_LICON, GetGadgetState(#WND_Join_Game_LICON), 2)) ; den index auslesen
ElseIf GadgetID = #WND_Join_Game_BTN_OK
Event = #PB_EventCloseWindow
ElseIf GadgetID = #WND_Join_Game_BTN_Abbruch
back = -1
Event = #PB_EventCloseWindow
EndIf
EndIf
Until Event = #PB_EventCloseWindow
Event = 0 ; nur dieses Fenster schliessen
; die anderen offenen Serververbindungen schliessen
ResetList(LAN_Client())
While NextElement(LAN_Client())
If LAN_Client()\Aktiv_Server And ListIndex(LAN_Client()) <> back ; wenn server, aber nicht der ausgewählte
CloseNetworkConnection(LAN_Client()\Aktiv_Server)
EndIf
Wend
CloseWindow(#WND_Join_Game)
EndIf
EndIf
ProcedureReturn back
EndProcedure
; Welche Clients gibts im Lan
Debug "get lan list"
GetLANList()
;{ teste die Lan-Computer auf Spiel-Server
port.l = 1000
c.l = 0
ResetList(LAN_Client())
While NextElement(LAN_Client())
Debug Str(ListIndex(LAN_Client())) + "- " + LAN_Client()\Name + " -> " + LAN_Client()\IP_Name
; auf welchen Clients läuft ein Server für das Spiel
NetzwerkID = OpenNetworkConnection(LAN_Client()\IP_Name, port)
If NetzwerkID ; wenn die Verbindung aufgebaut werden konnte
LAN_Client()\Aktiv_Server = NetzwerkID
Debug "netzwerkID gefunden: " + Str(NetzwerkID)
Msg.s = Space(20)
If ReceiveNetworkData(NetzwerkID, @Msg, 20)
Debug "received: " + Msg
LAN_Client()\Spieler_bisher = Val(Left(Msg, 1))
Msg = RTrim(Msg)
LAN_Client()\Spiel_Name = Right(Msg, Len(Msg)-1)
Debug "Spiel gefunden: " + LAN_Client()\Spiel_Name
c + 1
EndIf
EndIf
Wend
Debug "alle server getestet"
ResetList(LAN_Client())
While NextElement(LAN_Client())
; zeigt die gefunden server, wenn die letzte Zahl <> 0, läuft dort ein Server
Debug Str(ListIndex(LAN_Client())) + "- " + LAN_Client()\Name + " -> " + LAN_Client()\IP_Name + " - Erg: " + Str(LAN_Client()\Aktiv_Server)
Wend
;}
;{ Auswählen, welches Spiel mitgespielt werden soll
Anmeldung.l = 0 ; 1, wenn angelemdet
If c
t = Open_WND_Join_Game() ; wählt ein Spiel aus und schliesst die offenen Verbindungen zu anderen Spielservern
Debug "t: " + Str(t)
If t > -1 ; Spiel wurde ausgewählt
; die Verbindungsdaten übertragen
SelectElement(LAN_Client(), t)
Debug "listindex: " + Str(ListIndex(LAN_Client()))
NetzwerkID = LAN_Client()\Aktiv_Server
SpielName.s = LAN_Client()\Spiel_Name
; die Anmeldung am Spielserver machen
Debug "verbindungsdaten: ID: " + Str(NetzwerkID) + ". " + SpielName
Msg = "1" ; Bitte um Anmeldung beim Spiel
SendNetworkData(NetzwerkID, @Msg, 1) ; anmeldung für Spiel schicken
Msg = " !"
Repeat ; warte auf die Anmeldebestätigung
If NetworkClientEvent(NetzwerkID) = 2
ReceiveNetworkData(NetzwerkID, @Msg, 3)
EndIf
Debug "anmeldestring: " + Msg
Anmeldung = Val(Left(Msg, 1))
Debug "Anmeldung erhalten: " + Str(Anmeldung)
Delay(100) ; 10 Abfragen pro Sek langen
Until Anmeldung <> 0
EndIf
Else
MessageRequester("Problem", "Keine Spiele zum mitspielen vorhanden")
End
EndIf
;}
If Anmeldung = 1 ; nur starten, wenn angemeldet
MessageRequester("Angemeldet", Str(Anmeldung))
; hier beginnt nun das Spiel...
Else
MessageRequester("Fehler", "Konnte nicht an den gewünschten Spiel teilnehmen")
End
EndIf
Code: Alles auswählen
#MAX_CLIENTS = 8
Dim Client.l(#MAX_CLIENTS)
;{ Den Server erstellen
OpenConsole()
If InitNetwork() = 0
PrintN("Das Netzwerksystem konnte nicht gestartet werden")
Delay(3000)
End
EndIf
port = 1000 ; Alternativ dazu kann der Port auch eingegeben werden... (1000 wird von Clinet verwendet, muss also dort angepasst werden)
;PrintN("An welchem Port soll der Server lauschen?")
;port=Val(Input())
PrintN("")
PrintN("Geben Sie den Spielnamen an (max. 19 Zeichen)?")
SpielName.s =Input()
If Len(SpielName) > 19
SpielName = Left(SpielName, 19)
EndIf
PrintN("")
PrintN("SpielName: " + SpielName)
PrintN("")
If CreateNetworkServer(port) = 0
PrintN("Server konnte nicht erstellt werden")
Delay(3000)
End
Else
PrintN("Server wurde erstellt")
EndIf
;}
;{ Die Aktionsschleife
Repeat
Select NetworkServerEvent()
Case 1 ;{ a new client has been connected to the server
t = NetworkClientID()
c.l = 0
For x = 0 To #MAX_CLIENTS
If Client(x) <> 0
c + 1
EndIf
Next
Msg.s = Str(c) + SpielName
Msg = Msg + Space(20 - Len(Msg))
SendNetworkData(t, @Msg, 20) ; sendet die bisherige Spieleranzahl und den SPielnamen
PrintN("Serverabfrage - ID: " + Str(t))
;}
Case 2 ;{ Raw Data has been received (To be Read with ReceiveNetworkData())
t = NetworkClientID() ; sender speichern
; testen, ob Sender in Liste eingetragen
cnt.l = -1 ; nächster freier Platz
x.l = -1 ; index des Spielers mit Daten
For y = 0 To #MAX_CLIENTS
If Client(y) = t
x = y
EndIf
If Client(y) = 0 And cnt = -1
cnt = y
EndIf
Next
Debug "x: " + Str(x)
If x > -1 ; wenn schon in der Clientliste
; spezifische Datenverarbeitung
Debug "Erhalte daten von spieler (platz) " + Str(y) + " - verb: " + Str(t)
; Hier nun die Spielspezifische Datenverarbeitung
Else
Debug "neuer client sendet daten"
; Will sich der Client anmelden?
Msg.s = " " ; erwarte einen Anmeldestring
ReceiveNetworkData(t, @Msg, 1)
Debug "gesendet: " + Msg
If Msg = "1" ; Anmeldeversuch
If cnt > -1 ; wenn noch Platz in der Clientliste war
Client(cnt) = t ; in die Liste aufnehmen
PrintN("Neuer Client auf platz " + Str(cnt) + " - NR. " + Str(Client(cnt)))
Msg.s = "1-" + Str(cnt)
SendNetworkData(t, @Msg, 3) ; sende dem Client - Bestätigung Warteliste
Debug "bestätigung verschickt: " + Msg
Else
PrintN("Neuer Client versuchte sich einzuloggen - kein Platz auf Liste")
Msg.s = "9-"
SendNetworkData(t, @Msg, 2) ; sende dem Client - Absage wegen Voll
Debug "absage geschickt: " + Msg
EndIf
EndIf
EndIf
;}
Case 3 ; a file has been received (To be Read with ReceiveNetworkFile())
Case 4 ;{ a client has quit the server (deconnection)
t = NetworkClientID() ; sender speichern
; testen, ob Sender in Liste eingetragen
c.l = 0
For x = 0 To #MAX_CLIENTS
If Client(x) = t
Client(x) = 0 ; aus der Liste austragen
PrintN("Client hat sich ausgeloggt - Nr: " + Str(x))
c + 1
; evtl. Meldung an die anderen Spieler
EndIf
Next
If c = 0
PrintN("Ein Anfrager hat sich ausgeloggt - ID: " + Str(t))
EndIf
;}
EndSelect
Delay(1)
ForEver
;}
Zu guter letzt noch ne Verständnisfrage: Wenn ich das ganze übers Internet spielen will, müsste ich nur die IP-ADresse und den Port für den Server beim Client eingeben (und dafür die Suche weglassen) - Stimmt das?