1 /** 2 Helper class to implement a UDP server. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.udpserver; 14 import std.meta : AliasSeq, staticIndexOf; 15 import std.traits : Unqual; 16 import godot.d.traits; 17 import godot.core; 18 import godot.c; 19 import godot.d.bind; 20 import godot.d.reference; 21 import godot.globalenums; 22 import godot.object; 23 import godot.classdb; 24 import godot.reference; 25 import godot.packetpeerudp; 26 /** 27 Helper class to implement a UDP server. 28 29 A simple server that opens a UDP socket and returns connected $(D PacketPeerUDP) upon receiving new packets. See also $(D PacketPeerUDP.connectToHost). 30 After starting the server ($(D listen)), you will need to $(D poll) it at regular intervals (e.g. inside $(D Node._process)) for it to process new packets, delivering them to the appropriate $(D PacketPeerUDP), and taking new connections. 31 Below a small example of how it can be used: 32 33 34 # server.gd 35 extends Node 36 37 var server := UDPServer.new() 38 var peers = [] 39 40 func _ready(): 41 server.listen(4242) 42 43 func _process(delta): 44 server.poll() # Important! 45 if server.is_connection_available(): 46 var peer : PacketPeerUDP = server.take_connection() 47 var pkt = peer.get_packet() 48 print("Accepted peer: %s:%s" % $(D peer.get_packet_ip(), peer.get_packet_port())) 49 print("Received data: %s" % $(D pkt.get_string_from_utf8())) 50 # Reply so it knows we received the message. 51 peer.put_packet(pkt) 52 # Keep a reference so we can keep contacting the remote peer. 53 peers.append(peer) 54 55 for i in range(0, peers.size()): 56 pass # Do something with the connected peers. 57 58 59 60 61 62 # client.gd 63 extends Node 64 65 var udp := PacketPeerUDP.new() 66 var connected = false 67 68 func _ready(): 69 udp.connect_to_host("127.0.0.1", 4242) 70 71 func _process(delta): 72 if !connected: 73 # Try to contact server 74 udp.put_packet("The answer is... 42!".to_utf8()) 75 if udp.get_available_packet_count() > 0: 76 print("Connected: %s" % udp.get_packet().get_string_from_utf8()) 77 connected = true 78 79 80 */ 81 @GodotBaseClass struct UDPServer 82 { 83 package(godot) enum string _GODOT_internal_name = "UDPServer"; 84 public: 85 @nogc nothrow: 86 union { /** */ godot_object _godot_object; /** */ Reference _GODOT_base; } 87 alias _GODOT_base this; 88 alias BaseClasses = AliasSeq!(typeof(_GODOT_base), typeof(_GODOT_base).BaseClasses); 89 package(godot) __gshared bool _classBindingInitialized = false; 90 package(godot) static struct GDNativeClassBinding 91 { 92 __gshared: 93 @GodotName("get_max_pending_connections") GodotMethod!(long) getMaxPendingConnections; 94 @GodotName("is_connection_available") GodotMethod!(bool) isConnectionAvailable; 95 @GodotName("is_listening") GodotMethod!(bool) isListening; 96 @GodotName("listen") GodotMethod!(GodotError, long, String) listen; 97 @GodotName("poll") GodotMethod!(GodotError) poll; 98 @GodotName("set_max_pending_connections") GodotMethod!(void, long) setMaxPendingConnections; 99 @GodotName("stop") GodotMethod!(void) stop; 100 @GodotName("take_connection") GodotMethod!(PacketPeerUDP) takeConnection; 101 } 102 /// 103 pragma(inline, true) bool opEquals(in UDPServer other) const 104 { return _godot_object.ptr is other._godot_object.ptr; } 105 /// 106 pragma(inline, true) typeof(null) opAssign(typeof(null) n) 107 { _godot_object.ptr = n; return null; } 108 /// 109 pragma(inline, true) bool opEquals(typeof(null) n) const 110 { return _godot_object.ptr is n; } 111 /// 112 size_t toHash() const @trusted { return cast(size_t)_godot_object.ptr; } 113 mixin baseCasts; 114 /// Construct a new instance of UDPServer. 115 /// Note: use `memnew!UDPServer` instead. 116 static UDPServer _new() 117 { 118 static godot_class_constructor constructor; 119 if(constructor is null) constructor = _godot_api.godot_get_class_constructor("UDPServer"); 120 if(constructor is null) return typeof(this).init; 121 return cast(UDPServer)(constructor()); 122 } 123 @disable new(size_t s); 124 /** 125 126 */ 127 long getMaxPendingConnections() const 128 { 129 checkClassBinding!(typeof(this))(); 130 return ptrcall!(long)(GDNativeClassBinding.getMaxPendingConnections, _godot_object); 131 } 132 /** 133 Returns `true` if a packet with a new address/port combination was received on the socket. 134 */ 135 bool isConnectionAvailable() const 136 { 137 checkClassBinding!(typeof(this))(); 138 return ptrcall!(bool)(GDNativeClassBinding.isConnectionAvailable, _godot_object); 139 } 140 /** 141 Returns `true` if the socket is open and listening on a port. 142 */ 143 bool isListening() const 144 { 145 checkClassBinding!(typeof(this))(); 146 return ptrcall!(bool)(GDNativeClassBinding.isListening, _godot_object); 147 } 148 /** 149 Starts the server by opening a UDP socket listening on the given port. You can optionally specify a `bind_address` to only listen for packets sent to that address. See also $(D PacketPeerUDP.listen). 150 */ 151 GodotError listen(in long port, in String bind_address = gs!"*") 152 { 153 checkClassBinding!(typeof(this))(); 154 return ptrcall!(GodotError)(GDNativeClassBinding.listen, _godot_object, port, bind_address); 155 } 156 /** 157 Call this method at regular intervals (e.g. inside $(D Node._process)) to process new packets. And packet from known address/port pair will be delivered to the appropriate $(D PacketPeerUDP), any packet received from an unknown address/port pair will be added as a pending connection (see $(D isConnectionAvailable), $(D takeConnection)). The maximum number of pending connection is defined via $(D maxPendingConnections). 158 */ 159 GodotError poll() 160 { 161 checkClassBinding!(typeof(this))(); 162 return ptrcall!(GodotError)(GDNativeClassBinding.poll, _godot_object); 163 } 164 /** 165 166 */ 167 void setMaxPendingConnections(in long max_pending_connections) 168 { 169 checkClassBinding!(typeof(this))(); 170 ptrcall!(void)(GDNativeClassBinding.setMaxPendingConnections, _godot_object, max_pending_connections); 171 } 172 /** 173 Stops the server, closing the UDP socket if open. Will close all connected $(D PacketPeerUDP) accepted via $(D takeConnection) (remote peers will not be notified). 174 */ 175 void stop() 176 { 177 checkClassBinding!(typeof(this))(); 178 ptrcall!(void)(GDNativeClassBinding.stop, _godot_object); 179 } 180 /** 181 Returns the first pending connection (connected to the appropriate address/port). Will return `null` if no new connection is available. See also $(D isConnectionAvailable), $(D PacketPeerUDP.connectToHost). 182 */ 183 Ref!PacketPeerUDP takeConnection() 184 { 185 checkClassBinding!(typeof(this))(); 186 return ptrcall!(PacketPeerUDP)(GDNativeClassBinding.takeConnection, _godot_object); 187 } 188 /** 189 Define the maximum number of pending connections, during $(D poll), any new pending connection exceeding that value will be automatically dropped. Setting this value to `0` effectively prevents any new pending connection to be accepted (e.g. when all your players have connected). 190 */ 191 @property long maxPendingConnections() 192 { 193 return getMaxPendingConnections(); 194 } 195 /// ditto 196 @property void maxPendingConnections(long v) 197 { 198 setMaxPendingConnections(v); 199 } 200 }