Sorry für den Doppelpost (aber sonst hätte niemand etwas davon mitbekommen)
Es gibt jetzt eine Version 1.1 welche das neuste ENet 1.3.13 verwendet (siehe 1. Post). Hier noch den Quellcode dazu, falls die Download-Links oben einmal nicht funktionieren sollten:
net.bmx (Hauptdatei des Moduls)
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict
Module mzehr.net
ModuleInfo "Version 2.0" ModuleInfo "Author: Michael Zehr (Jolinah)" ModuleInfo "License: MIT X11 License (License.txt)" ModuleInfo "Credit: Lee Salzman (http://enet.bespin.org)"
ModuleInfo "History: 1.0 First release" ModuleInfo "History: 1.1 Instead of importing pub.enet, the newest source code of ENet has been compiled into the module (version 1.3.13 as of now). However, the protocol of ENet version 1.3 and above is not compatible with ENet versions 1.2 and below. You will need to redistribute the client to all existing players after updating the server or they won't be able to play on the new server."
Import brl.linkedlist Import brl.bank Import brl.bankstream
Import pub.zlib
Import "enet/enet/*.h" Import "enet/callbacks.c" Import "enet/compress.c" Import "enet/host.c" Import "enet/list.c" Import "enet/packet.c" Import "enet/peer.c" Import "enet/protocol.c"
?Win32 Import "enet/win32.c" Import "-lws2_32" Import "-lwinmm" ?MacOs Import "enet/unix.c" ?Linux Import "enet/unix.c" ?
Include "TNetServer.bmx" Include "TNetPeer.bmx" Include "TNetClient.bmx" Include "TNetEvent.bmx" Include "TNetPacket.bmx"
Type ENetEvent Field event:Int Field peer:Byte Ptr Field channelID:Byte Field data:Int Field packet:Byte Ptr End Type
Extern "C" Const ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT:Int = 1 Const ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT:Int = 255 Const ENET_HOST_ANY:Int = 0 Const ENET_PACKET_FLAG_RELIABLE:Int = 0 Const ENET_PACKET_FLAG_UNSEQUENCED:Int = 1
Function enet_address_get_host:Int(address:Byte Ptr, HostName$z, nameLength:Int) Function enet_address_get_host_ip:Int(address:Byte Ptr, HostName$z, nameLength:Int) Function enet_address_set_host:Int(address:Byte Ptr, HostName$z) Function enet_deinitialize() Function enet_initialize:Int() Function enet_initialize_with_callbacks:Int(version:Int, inits:Byte Ptr) Function enet_linked_version:Int() Function enet_host_bandwith_limit(host:Byte Ptr, incomingBandwith:Int, outgoingBandwith:Int) Function enet_host_broadcast(host:Byte Ptr, channelID:Byte, packet:Byte Ptr) Function enet_host_channel_limit(host:Byte Ptr, channelLimit:Int) Function enet_host_check_events:Int(host:Byte Ptr, event:Byte Ptr) Function enet_host_compress(host:Byte Ptr, compressor:Byte Ptr) Function enet_host_compress_with_range_coder:Int(host:Byte Ptr) Function enet_host_connect:Byte Ptr(host:Byte Ptr, address:Byte Ptr, channelCount:Int, data:Int = 0) Function enet_host_create:Byte Ptr(address:Byte Ptr, peerCount:Int, channelLimit:Int, incomingBandwith:Int, outgoingBandwith:Int) Function enet_host_destroy(host:Byte Ptr) Function enet_host_flush(host:Byte Ptr) Function enet_host_service:Int(host:Byte Ptr, event:Byte Ptr, timeout:Int) Function enet_packet_create:Byte Ptr(data:Byte Ptr, dataLength:Int, flags:Int) Function enet_packet_destroy(packet:Byte Ptr) Function enet_packet_resize:Int(packet:Byte Ptr, dataLength:Int) Function enet_peer_disconnect(peer:Byte Ptr, data:Int = 0) Function enet_peer_disconnect_later(peer:Byte Ptr, data:Int = 0) Function enet_peer_disconnect_now(peer:Byte Ptr, data:Int = 0) Function enet_peer_ping(peer:Byte Ptr) Function enet_peer_ping_interval(peer:Byte Ptr, pingInterval:Int) Function enet_peer_receive:Byte Ptr(peer:Byte Ptr, channelID:Byte Ptr) Function enet_peer_reset(peer:Byte Ptr) Function enet_peer_send:Int(peer:Byte Ptr, channelID:Byte, packet:Byte Ptr) Function enet_peer_throttle_configure(peer:Byte Ptr, interval:Int, acceleration:Int, deceleration:Int) Function enet_peer_timeout(peer:Byte Ptr, timeoutLimit:Int, timeoutMinimum:Int, timeoutMaximum:Int) End Extern
Function enet_peer_address(peer:Byte Ptr, host_ip:Int Var, host_port:Int Var) Local ip:Int = (Int Ptr peer)[3] Local port:Int = (Short Ptr peer)[8] ?LittleEndian ip = (ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24) ? host_ip = ip host_port = port End Function
Function enet_packet_data:Byte Ptr(packet:Byte Ptr) Return Byte Ptr((Int Ptr packet)[2]) End Function
Function enet_packet_size:Int(packet:Byte Ptr) Return (Int Ptr packet)[3] End Function
Function enet_address_create:Byte Ptr(host_ip:Int, host_port:Int) Local t:Byte Ptr = MemAlloc(6) ?BigEndian (Int Ptr t)[0] = host_ip ?LittleEndian (Int Ptr t)[0] = (host_ip Shr 24) | (host_ip Shr 8 & $ff00) | (host_ip Shl 8 & $ff0000) | (host_ip Shl 24) ? (Short Ptr t)[2] = host_port Return t End Function
Function enet_address_destroy(address:Byte Ptr) MemFree address End Function
enet_initialize() atexit_(enet_deinitialize)
TNetClient.bmx
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Type TNetClient Field _host:Byte Ptr Field _peer:Byte Ptr
Function Create:TNetClient() Local client:TNetClient = New TNetClient Return client End Function
Method Connect:Int(host:String, port:Int, connectTimeout:Int = 5000, channelCount:Int = 2) Disconnect() Local addr:Byte Ptr = enet_address_create(0, port) If addr = Null Then Return False enet_address_set_host(addr, host)
If channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT ElseIf channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT End If _host = enet_host_create(Null, 1, channelCount, 0, 0) If _host = Null Then Return False
_peer = enet_host_connect(_host, addr, channelCount) enet_address_destroy(addr)
If _peer = Null Then enet_host_destroy(_host) _host = Null Return False EndIf Local ev:ENetEvent = New ENetEvent If enet_host_service(_host, ev, connectTimeout) > 0 And ev.event = TNetClientEvent.CONNECT Return True Else enet_peer_reset(_peer) enet_host_destroy(_host) _host = Null _peer = Null Return False End If End Method
Method Disconnect(disconnectTime:Int = 2000) If _host = Null And _peer = Null Then Return
If _peer = Null Then enet_host_destroy(_host) _host = Null Return End If If _host = Null Then enet_peer_reset(_peer) _peer = Null Return End If If disconnectTime <= 0 Then enet_peer_reset(_peer) enet_host_destroy(_host) _host = Null _peer = Null Return End If Local ev:ENetEvent = New ENetEvent Local begin:Int = MilliSecs()
enet_peer_disconnect(_peer) While enet_host_service(_host, ev, disconnectTime) > 0 Select ev.event Case TNetClientEvent.DATA enet_packet_destroy(ev.packet)
Case TNetClientEvent.DISCONNECT Exit End Select If MilliSecs() - begin >= disconnectTime Then Exit Wend enet_peer_reset(_peer) enet_host_destroy(_host) _host = Null _peer = Null End Method
Method Update:TNetClientEvent(waitTime:Int = 0) If _host = Null Then Return Null Local ev:ENetEvent = New ENetEvent If enet_host_service(_host, ev, waitTime) > 0 Select ev.event Case TNetClientEvent.DATA Return TNetClientEvent.ClientEvent(ev.event, TNetPacket.FromEnet(ev.packet), ev.channelID) Case TNetClientEvent.DISCONNECT Return TNetClientEvent.ClientEvent(ev.event, Null, 0) End Select Else Return Null End If End Method
Method Send(packet:TNetPacket, reliable:Int = False, channel:Int = 0, compressed:Int = False) If packet = Null Then Return If _host = Null Or _peer = Null Then Return Local flags:Int = 0 If reliable Then flags = ENET_PACKET_FLAG_RELIABLE Local p:Byte Ptr = packet.EnetPacket(flags, compressed) If p = Null Then Return enet_peer_send(_peer, channel, p) End Method
Method Flush() If _host = Null Then Return enet_host_flush(_host) End Method End Type
TNetEvent.bmx
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Type TNetClientEvent
Const CONNECT:Int = 1
Const DISCONNECT:Int = 2
Const DATA:Int = 3
Field Event:Int
Field Packet:TNetPacket
Field Channel:Int Function ClientEvent:TNetClientEvent(event:Int, packet:TNetPacket, channel:Int) Local ev:TNetClientEvent = New TNetClientEvent ev.event = event ev.packet = packet ev.channel = channel Return ev End Function End Type
Type TNetServerEvent Extends TNetClientEvent
Field Peer:TNetPeer Function ServerEvent:TNetServerEvent(event:Int, packet:TNetPacket, peer:TNetPeer, channel:Int) Local ev:TNetServerEvent = New TNetServerEvent ev.event = event ev.packet = packet ev.peer = peer ev.channel = channel Return ev End Function End Type
TNetPacket.bmx
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Type TNetPacket Field _packet:Byte Ptr Field _bank:TBank Field _stream:TBankStream
Function Create:TNetPacket() Local packet:TNetPacket = New TNetPacket packet._bank = TBank.Create(0) packet._stream = TBankStream.Create(packet._bank) packet.WriteByte(0) Return packet End Function
Function FromEnet:TNetPacket(p:Byte Ptr) Local packet:TNetPacket = New TNetPacket packet._packet = p packet._bank = TBank.CreateStatic(enet_packet_data(p), enet_packet_size(p)) packet._stream = TBankStream.Create(packet._bank)
Local cmp:Byte = packet.ReadByte() If cmp Then Local buf:Byte Ptr = MemAlloc(packet._bank.Size() - 1) Local l:Int = 0 uncompress(buf, l, Varptr packet._bank.buf()[1], packet._bank.Size() - 1) packet._stream.Close() packet._bank = TBank.Create(l) packet._stream = TBankStream.Create(packet._bank) MemCopy(packet._bank.buf(), buf, l) MemFree(buf) End If Return packet End Function
Method Delete() Destroy() End Method
Method Destroy() If _stream <> Null Then _stream.Close() _stream = Null End If If _bank <> Null Then _bank = Null End If If _packet <> Null Then enet_packet_destroy(_packet) _packet = Null End If End Method
Method Read:Int(buf:Byte Ptr, count:Int) Return _stream.Read(buf, count) End Method
Method ReadByte:Byte() Return _stream.ReadByte() End Method
Method ReadBytes:Int(buf:Byte Ptr, count:Int) Return _stream.ReadBytes(buf, count) End Method
Method ReadShort:Short() Return _stream.ReadShort() End Method
Method ReadInt:Int() Return _stream.ReadInt() End Method
Method ReadLong:Long() Return _stream.ReadLong() End Method
Method ReadFloat:Float() Return _stream.ReadFloat() End Method
Method ReadDouble:Double() Return _stream.ReadDouble() End Method
Method ReadString:String() Local l:Int = _stream.ReadInt() If l = -1 Then Return Null Return _stream.ReadString(l) End Method
Method ReadLine:String() Return _stream.ReadLine() End Method
Method ReadObject:Object() Return _stream.ReadObject() End Method
Method Write(buf:Byte Ptr, count:Int) _stream.Write(buf, count) End Method
Method WriteByte(value:Byte) _stream.WriteByte(value) End Method
Method WriteBytes(buf:Byte Ptr, count:Int) _stream.WriteBytes(buf, count) End Method
Method WriteShort(value:Short) _stream.WriteShort(value) End Method
Method WriteInt(value:Int) _stream.WriteInt(value) End Method
Method WriteLong(value:Long) _stream.WriteLong(value) End Method
Method WriteFloat(value:Float) _stream.WriteFloat(value) End Method
Method WriteDouble(value:Double) _stream.WriteDouble(value) End Method
Method WriteString(value:String) If value = 0 _stream.WriteInt(-1) Return Else _stream.WriteInt(value.Length) _stream.WriteString(value) End If End Method
Method WriteLine(value:String) _stream.WriteLine(value) End Method
Method WriteObject(value:Object) _stream.WriteObject(value) End Method
Method EnetPacket:Byte Ptr(enet_flags:Int = 0, compressed:Int = False) If _packet <> Null Then Return _packet If _bank = Null Then Return Null If compressed Then Local cmp:Byte Ptr = MemAlloc(_bank.Size() - 1) Local cmpLen:Int = 0 compress(cmp, cmpLen, Varptr _bank.buf()[1], _bank.Size() - 1) Local buf:Byte Ptr = MemAlloc(cmpLen + 1) MemCopy(Varptr buf[1], cmp, cmpLen) buf[0] = 1
Local p:Byte Ptr = enet_packet_create(buf, cmpLen + 1, enet_flags) MemFree(cmp) MemFree(buf) Return p Else Return enet_packet_create(_bank.buf(), _bank.Size(), enet_flags) End If End Method
End Type
TNetPeer.bmx
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Type TNetPeer Field _peer:Byte Ptr Field _data:Object
Function Create:TNetPeer(peer:Byte Ptr) Local p:TNetPeer = New TNetPeer p._peer = peer Return p End Function
Method GetPeer:Byte Ptr() Return _peer End Method
Method GetData:Object() Return _data End Method
Method SetData(value:Object) _data = value End Method End Type
TNetServer.bmx
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Type TNetServer Field _host:Byte Ptr Field _peers:TList Method New() _peers = New TList End Method
Function Create:TNetServer(ip:String, port:Int, maxConnections:Int, maxChannels:Int = 2) Local addr:Byte Ptr = enet_address_create(ENET_HOST_ANY, port) If addr = Null Then Return Null If ip <> Null And ip <> "" And ip <> "localhost" And ip <> "127.0.0.1" enet_address_set_host(addr, ip) End If If maxChannels < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT maxChannels = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT ElseIf maxChannels > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT maxChannels = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT End If Local host:Byte Ptr = enet_host_create(addr, maxConnections, maxChannels, 0, 0) enet_address_destroy(addr) If host = Null Then Return Null Local sv:TNetServer = New TNetServer sv._host = host Return sv End Function
Method Shutdown(shutdownTime:Int = 5000) If _host = Null Then Return Local p:TNetPeer = Null For p = EachIn _peers enet_peer_disconnect(p.GetPeer()) Next Local ev:ENetEvent = New ENetEvent Local begin:Int = MilliSecs() If shutdownTime > 0 Then While enet_host_service(_host, ev, shutdownTime) > 0 Select ev.event Case TNetServerEvent.CONNECT enet_peer_reset(ev.peer) Case TNetServerEvent.DATA enet_packet_destroy(ev.packet) Case TNetServerEvent.DISCONNECT p = FindPeer(ev.peer) If p <> Null Then _peers.Remove(p) End Select If _peers.IsEmpty() Then Exit If MilliSecs() - begin >= shutdownTime Then Exit Wend EndIf
If Not _peers.IsEmpty() Then For p = EachIn _peers enet_peer_reset(p) Next _peers.Clear() EndIf enet_host_destroy(_host) _host = Null End Method
Method Update:TNetServerEvent(waitTime:Int = 0) If _host = Null Then Return Null Local p:TNetPeer = Null Local ev:ENetEvent = New ENetEvent If enet_host_service(_host, ev, waitTime) > 0 Select ev.event Case TNetServerEvent.CONNECT p = TNetPeer.Create(ev.peer) _peers.AddLast(p) Return TNetServerEvent.ServerEvent(ev.event, Null, p, ev.channelID)
Case TNetServerEvent.DATA p = FindPeer(ev.peer) If p = Null Then Return Null Return TNetServerEvent.ServerEvent(ev.event, TNetPacket.FromEnet(ev.packet), p, ev.channelID)
Case TNetServerEvent.DISCONNECT p = FindPeer(ev.peer) If p = Null Then Return Null _peers.Remove(p) Return TNetServerEvent.ServerEvent(ev.event, Null, p, ev.channelID) End Select Else Return Null End If End Method
Method FindPeer:TNetPeer(peer:Byte Ptr) For Local p:TNetPeer = EachIn _peers If p.GetPeer() = peer Then Return p Next Return Null End Method
Method Send(peer:TNetPeer, packet:TNetPacket, reliable:Int = False, channel:Int = 0, compressed:Int = False) If _host = Null Or peer = Null Or packet = Null Then Return If peer.GetPeer() = Null Then Return Local flags:Int = 0 If reliable Then flags = ENET_PACKET_FLAG_RELIABLE Local p:Byte Ptr = packet.EnetPacket(flags, compressed) If p = Null Then Return enet_peer_send(peer.GetPeer(), channel, p) End Method
Method Broadcast(packet:TNetPacket, reliable:Int = False, channel:Int = 0, compressed:Int = False) If _host = Null Or packet = Null Then Return Local flags:Int = 0 If reliable Then flags = ENET_PACKET_FLAG_RELIABLE Local p:Byte Ptr = packet.EnetPacket(flags, compressed) If p = Null Then Return enet_host_broadcast(_host, channel, p) End Method
Method GetClients:TList() Return _peers End Method
Method Flush() If _host = Null Then Return enet_host_flush(_host) End Method
Method DisconnectClient(peer:TNetPeer) If peer = Null Or peer.GetPeer() = Null Then Return enet_peer_disconnect(peer.GetPeer()) End Method
Method DropClient(peer:TNetPeer) If peer = Null Or peer.GetPeer() = Null Then Return enet_peer_reset(peer.GetPeer()) _peers.Remove(peer) End Method End Type
Beispiele:
ExampleServer.bmx
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict
Import mzehr.net
AppTitle = "Server" SeedRnd(MilliSecs())
Type TPlayer Field Name:String Field Keys:Byte[] Field X:Float Field Y:Float Method New() Keys = New Byte[256] End Method
Method SetKey(code:Int, pressed:Int) If code >= 0 And code < Keys.Length Then Keys[code] = pressed End If End Method Method GetKey:Int(code:Int) If code >= 0 And code < Keys.Length Then Return Keys[code] Return False End Method End Type
Global server:TNetServer = TNetServer.Create(Null, 50000, 10)
If server = Null Then Notify("Der Server konnte nicht initialisiert werden.") End End If
Graphics 200, 200, 0
Local lastPosUpdate:Int = 0 Local numPosUpdates:Int = 10
Local deltaTime:Float = 0 Local lastFrame:Int = MilliSecs()
Repeat deltaTime = (MilliSecs() - lastFrame) / 1000.0 lastFrame = MilliSecs() Cls
Local event:TNetServerEvent = server.Update()
While event <> Null Select event.event Case TNetServerEvent.CONNECT Local player:TPlayer = New TPlayer player.X = Rand(20, 780) player.Y = Rand(20, 580) event.Peer.SetData(player) Case TNetServerEvent.DISCONNECT SendeTrennungsNachricht(event) event.Peer.SetData(Null) Case TNetServerEvent.DATA Local player:TPlayer = TPlayer(event.Peer.GetData())
If player.Name = Null Then DatenVerarbeitung_NichtAngemeldet(event) Else DatenVerarbeitung_Angemeldet(event) End If End Select event = server.Update() Wend For Local peer:TNetPeer = EachIn server.GetClients() Local player:TPlayer = TPlayer(peer.GetData())
player.X:+player.GetKey(KEY_LEFT) * -200 * deltaTime + player.GetKey(KEY_RIGHT) * 200 * deltaTime; player.Y:+player.GetKey(KEY_UP) * -200 * deltaTime + player.GetKey(KEY_DOWN) * 200 * deltaTime; If player.X < 0 player.X = 0 ElseIf player.X > 800 player.X = 800 EndIf If player.Y < 0 player.Y = 0 ElseIf player.Y > 600 player.Y = 600 End If Next If MilliSecs() - lastPosUpdate > 1000 / numPosUpdates Local paket:TNetPacket = TNetPacket.Create() paket.WriteByte(5) paket.WriteInt(server.GetClients().Count()) For Local peer:TNetPeer = EachIn server.GetClients() Local player:TPlayer = TPlayer(peer.GetData()) paket.WriteString(player.Name) paket.WriteFloat(player.X) paket.WriteFloat(player.Y) Next server.Broadcast(paket) lastPosUpdate = MilliSecs() EndIf
Flip -1 Until AppTerminate() Or KeyHit(KEY_ESCAPE)
EndGraphics
server.Shutdown()
End
Function DatenVerarbeitung_NichtAngemeldet(event:TNetServerEvent) Local player:TPlayer = TPlayer(event.Peer.GetData())
Local msgId:Byte = event.Packet.ReadByte()
Select msgId
Case 1 Local name:String = event.Packet.ReadString() If name = Null Or name.Length < 3 Then Local paket:TNetPacket = TNetPacket.Create() paket.WriteByte(1) paket.WriteByte(0) paket.WriteString("Dieser Name ist zu kurz.") server.Send(event.Peer, paket, True, 1) ElseIf FindPlayer(name) <> Null Local paket:TNetPacket = TNetPacket.Create() paket.WriteByte(1) paket.WriteByte(0) paket.WriteString("Dieser Name wird bereits verwendet.") server.Send(event.Peer, paket, True, 1) Else player.name = name Local paket:TNetPacket = TNetPacket.Create() paket.WriteByte(1) paket.WriteByte(1) paket.WriteInt(server.GetClients().Count() - 1) For Local peer:TNetPeer = EachIn server.GetClients() If peer = event.peer Then Continue Local p:TPlayer = TPlayer(peer.GetData()) paket.WriteString(p.name) paket.WriteFloat(p.X) paket.WriteFloat(p.Y) Next server.Send(event.Peer, paket, True, 1)
SendeVerbindungsNachricht(event) EndIf End Select End Function
Function FindPlayer:TPlayer(name:String) name = name.ToLower()
For Local peer:TNetPeer = EachIn server.GetClients() Local player:TPlayer = TPlayer(peer.GetData()) If player <> Null And player.name.ToLower() = name Then Return player Next
Return Null End Function
Function DatenVerarbeitung_Angemeldet(event:TNetServerEvent) Local player:TPlayer = TPlayer(event.Peer.GetData())
Local msgId:Byte = event.Packet.ReadByte()
Select msgId
Case 4 Local code:Byte = event.Packet.ReadByte() Local pressed:Byte = event.Packet.ReadByte() player.SetKey(code, pressed) End Select End Function
Function SendeVerbindungsNachricht(event:TNetServerEvent) Local player:TPlayer = TPlayer(event.Peer.GetData())
Local paket:TNetPacket = TNetPacket.Create() paket.WriteByte(2) paket.WriteString(player.Name) paket.WriteFloat(player.X) paket.WriteFloat(player.Y) For Local client:TNetPeer = EachIn server.GetClients() If client = event.Peer Then Continue server.Send(client, paket, True, 1) Next
End Function
Function SendeTrennungsNachricht(event:TNetServerEvent) Local player:TPlayer = TPlayer(event.Peer.GetData()) Local paket:TNetPacket = TNetPacket.Create() paket.WriteByte(3) paket.WriteString(player.Name) For Local client:TNetPeer = EachIn server.GetClients() If client = event.Peer Then Continue server.Send(client, paket, True, 1) Next
End Function
ExampleClient.bmx
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict
Import mzehr.net
AppTitle = "Client" SeedRnd(MilliSecs())
Type TPlayer Global List:TList = New TList
Field Name:String Field X:Float Field Y:Float Field ZielX:Float Field ZielY:Float
Field Initialisiert:Int Method New() List.AddLast(Self) End Method Method Update(deltaTime:Float) X = Interpoliere(X, ZielX, 2.0 * deltaTime) Y = Interpoliere(Y, ZielY, 2.0 * deltaTime) End Method Method Draw() Local px:Int = Int(X) Local py:Int = Int(Y) DrawText(Name, px - TextWidth(Name) / 2, py - 40 - TextHeight(Name)) DrawOval(px - 10, py - 40, 20, 20) DrawLine(px, py - 30, px, py + 10) DrawLine(px, py - 10, px - 20, py - 30) DrawLine(px, py - 10, px + 20, py - 30) DrawLine(px, py + 10, px - 20, py + 30) DrawLine(px, py + 10, px + 20, py + 30) End Method End Type
Global client:TNetClient = TNetClient.Create()
Local myPlayer:TPlayer = New TPlayer myPlayer.Name = "Guest" + Rand(1000, 9999)
If client.Connect("localhost", 50000) Local paket:TNetPacket = TNetPacket.Create() paket.WriteByte(1) paket.WriteString(myPlayer.Name) client.Send(paket, True, 1) Local event:TNetClientEvent = client.Update(2000) If event <> Null And event.event = TNetClientEvent.DATA Local msgId:Byte = event.Packet.ReadByte() If msgId = 1 Local loggedIn:Int = event.Packet.ReadByte() If loggedIn Local numPlayers:Int = event.Packet.ReadInt() For Local i:Int = 0 To numPlayers - 1 Local name:String = event.Packet.ReadString() Local x:Float = event.Packet.ReadFloat() Local y:Float = event.Packet.ReadFloat() Local player:TPlayer = New TPlayer player.name = name player.X = x player.Y = y player.ZielX = x player.ZielY = y Next Else Local error:String = event.Packet.ReadString() client.Disconnect() Notify(error) End End If Else client.Disconnect() Notify("Der Server hat eine unerwartete Antwort gesendet. Protokoll-Fehler?") End End If Else client.Disconnect() Notify("Der Server hat innerhalb von 2 Sekunden keine Antwort gesendet. Verbindung fehlgeschlagen.") End End If Else Notify "Es konnte keine Verbindung hergestellt werden." End End If
Graphics 800, 600, 0
Local keyState:Byte[] = New Byte[256]
Local quitApp:String = Null
Local deltaTime:Float = 0 Local lastFrame:Int = MilliSecs()
Repeat deltaTime = (MilliSecs() - lastFrame) / 1000.0 lastFrame = MilliSecs() Cls
UpdateKey(KEY_UP, keyState[KEY_UP]) UpdateKey(KEY_DOWN, keyState[KEY_DOWN]) UpdateKey(KEY_LEFT, keyState[KEY_LEFT]) UpdateKey(KEY_RIGHT, keyState[KEY_RIGHT])
Local event:TNetClientEvent = client.Update() While event <> Null Select event.event Case TNetClientEvent.DISCONNECT quitApp = "Der Server hat die Verbindung getrennt." Case TNetClientEvent.DATA DatenVerarbeitung(event) End Select event = client.Update() Wend
For Local player:TPlayer = EachIn TPlayer.List player.Update(deltaTime) player.Draw() Next
Flip -1 Until AppTerminate() Or KeyHit(KEY_ESCAPE) Or quitApp <> Null
EndGraphics
client.Disconnect()
If quitApp <> Null Then Notify(quitApp)
End
Function FindPlayer:TPlayer(name:String) name = name.ToLower()
For Local player:TPlayer = EachIn TPlayer.List If player.name.ToLower() = name Then Return player Next Return Null End Function
Function UpdateKey(code:Int, lastState:Byte Var) Local update:Int = False
If KeyDown(code) And Not lastState Then lastState = True update = True Else If lastState And Not KeyDown(code) Then lastState = False update = True End If If update Then Local paket:TNetPacket = TNetPacket.Create() paket.WriteByte(4) paket.WriteByte(code) paket.WriteByte(lastState) client.Send(paket, True, 1) End If End Function
Function DatenVerarbeitung(event:TNetClientEvent)
Local msgId:Byte = event.Packet.ReadByte() Select msgId Case 2 Local name:String = event.Packet.ReadString() Local x:Float = event.Packet.ReadFloat() Local y:Float = event.Packet.ReadFloat()
Local player:TPlayer = New TPlayer player.Name = name player.X = x player.Y = y player.ZielX = x player.ZielY = y Case 3 Local name:String = event.Packet.ReadString() Local player:TPlayer = FindPlayer(name) If player <> Null Then TPlayer.List.Remove(player) Case 5 Local numPlayers:Int = event.Packet.ReadInt() For Local i:Int = 0 To numPlayers - 1 Local name:String = event.Packet.ReadString() Local x:Float = event.Packet.ReadFloat() Local y:Float = event.Packet.ReadFloat() Local player:TPlayer = FindPlayer(name) If player <> Null Then If Not player.Initialisiert player.X = x player.Y = y player.Initialisiert = True End If player.ZielX = x player.ZielY = y End If Next End Select End Function
Function Interpoliere:Float(aktuell:Float, neu:Float, faktor:Float) faktor = Clamp01(faktor) Return ((1.0 - faktor) * aktuell) + (faktor * neu) End Function
Function Clamp01:Float(wert:Float) If wert < 0.0 Then Return 0.0 If wert > 1.0 Then Return 1.0 Return wert End Function
Ausserdem wird natürlich der Quellcode von ENet benötigt, zu finden unter https://github.com/lsalzman/enet.
Die .c-Dateien müssen in den Modul-Unterordner "enet" kopiert werden.
Die .h-Dateien müssen in den Modul-Unterordner "enet/enet" kopiert werden. (NICHT enet/include/enet)
Die .h-Dateien müssen nachträglich editiert werden: Bei allen #include "enet/datei.h" muss der enet-Ordner aus dem Pfad entfernt werden, sprich #include "datei.h"
|