diff --git a/hamncheese/Scripts/main.gd b/hamncheese/Scripts/main.gd index 724676e..6fe5046 100644 --- a/hamncheese/Scripts/main.gd +++ b/hamncheese/Scripts/main.gd @@ -56,8 +56,10 @@ func _data_recieved(type, data): #***TODO**** We should really be displaying things in columns. var root = peers_tree.create_item() for peer in Peers.peerArray: - var child = peers_tree.create_item(root) - child.set_text(0, peer["user"] + " (" + peer["ip"] + ") " + str(peer["ping"]) + "ms") + print(peer["online"]) + if peer["online"]: + var child = peers_tree.create_item(root) + child.set_text(0, peer["user"] + " (" + peer["ip"] + ")") # Handle empty peer list. if data.size() == 0 and peers_tree.get_root() != null: peers_tree.clear() diff --git a/hamncheese/Scripts/network.gd b/hamncheese/Scripts/network.gd new file mode 100644 index 0000000..fb2b1af --- /dev/null +++ b/hamncheese/Scripts/network.gd @@ -0,0 +1,24 @@ +extends Node + + +func _process(_delta): + pass + + +func _ready(): + Peers.peer_received_packet.connect(_received_packet) + + +func _received_packet(peer, verb, payload): + match verb: + "online": + if peer["online"] != payload["status"]: + peer["online"] = payload["status"] + peer["refresh"] = true + + _: + print("UNKNOWN PACKET") + print(peer) + print(verb) + print(payload) + print() diff --git a/hamncheese/Scripts/peers.gd b/hamncheese/Scripts/peers.gd index db5b2aa..254a8f1 100644 --- a/hamncheese/Scripts/peers.gd +++ b/hamncheese/Scripts/peers.gd @@ -1,17 +1,15 @@ extends Node -const ENET_SERVICE_EVENT_TYPE = 0 -const ENET_SERVICE_PEER = 1 -const ENET_SERVICE_EVENT_DATA = 2 -const ENET_SERVICE_EVENT_CHANNEL = 3 +signal peer_received_packet(peer, verb, payload) -var _basePort: int +var _tcp := TCPServer.new() +var _basePort : int var _serverRunning: bool +var _timer : Timer # This array is of dictionary elements that contain: -# "enet": ENet listening connnection. # "id": Unique ID of this peer (1-254) based on IP. # "ip": IP address of this peer. # "port": Listen port of this peer. @@ -20,10 +18,10 @@ var _serverRunning: bool var _userInfo: Dictionary # This array is of dictionary elements that contain: -# "enet": ENet connection to this host. +# "tcp": TCP connection to this peer. # "id": Unique ID of this peer (1-254) based on IP. # "ip": IP address of this peer. -# "online": Will be true except when used to update the array. +# "online": Will be true when TCP network can talk to the peer. # "port": Listen port of this peer. # "user": User name on this IP. # "uuid": UUID for this peer. @@ -44,50 +42,30 @@ var _userInfo: Dictionary var peerArray: Array +func _on_timer_timeout(): + if _serverRunning: + # Tell everyone we're alive. + for peer in peerArray: + if peer["tcp"] != null: + peer["tcp"].poll() + if peer["tcp"].get_status() == StreamPeerTCP.STATUS_CONNECTED: + send_to_peer(peer, "online", { "status": true }) + + func _process(_delta): if _serverRunning: - # Handle current connections. - _process_enet(_userInfo["enet"], _userInfo["id"]) - # Manage peer connections. - for peer in peerArray: - # Do we need new connections? It looks funny that we check for both connected and - # disconnected but there are other states the peer could be in. - if !is_peer_valid(peer): - print("Connecting to ", peer["ip"], ":", peer["port"]) - peer["enet"] = _userInfo["enet"].connect_to_host(peer["ip"], peer["port"], 0) - else: - # Do we need to remove this one? - if is_peer_disconnected(peer): - peer["enet"] = null - - -func _process_enet(host: ENetConnection, id: int): - if host == null: - return - var ret = host.service() # Returns an array of ENET_SERVICE_* items. - match ret[ENET_SERVICE_EVENT_TYPE]: - host.EVENT_CONNECT: - print("Peer connected ", id, " (", host.get_peers().size(), " known peers)") - #var enet_peers = host.get_peers() - #for enet_peer in enet_peers: - - host.EVENT_DISCONNECT: - print("Peer disconnected ", id, " (", host.get_peers().size(), " known peers)") - - host.EVENT_ERROR: - print("Peer error ", id, " (", host.get_peers().size(), " known peers)") - #***TODO*** Attempt disconnect/reconnect - - host.EVENT_NONE: - pass - - host.EVENT_RECEIVE: - print("Peer recieved data ", id, " (", host.get_peers().size(), " known peers)") + _tcp_server() func _ready(): _serverRunning = false clear() + _timer = Timer.new() + _timer.wait_time = 1 + _timer.one_shot = false + _timer.timeout.connect(_on_timer_timeout) + Engine.get_main_loop().current_scene.add_child(_timer) + _timer.start() func _sort_by_ip(a, b): @@ -97,35 +75,70 @@ func _sort_by_ip(a, b): return false +func _tcp_server(): + if _tcp.is_listening(): + # New inbound connection. + if _tcp.is_connection_available(): + var new_peer: StreamPeerTCP = _tcp.take_connection() + # Do we have a connection for this peer already? + for peer in peerArray: + if peer["ip"] == new_peer.get_connected_host(): + if peer["tcp"] == null: + # No - add it! + peer["tcp"] = new_peer + print("New peer ", peer["ip"], ":", peer["port"]) + else: + # Yes. Close existing, use this one. + peer["tcp"].disconnect_from_host() + peer["tcp"] = new_peer + print("Updated peer ", peer["ip"], ":", peer["port"]) + peer["tcp"].set_no_delay(true) + + # Process incoming data and attempt connections. + for peer in peerArray: + if peer["tcp"] == null: + # Try to connect. + print("Connecting to ", peer["ip"], ":", peer["port"]) + peer["tcp"] = StreamPeerTCP.new() + var error = peer["tcp"].connect_to_host(peer["ip"], peer["port"]) + if error == OK: + peer["tcp"].set_no_delay(true) + else: + peer["tcp"] = null + else: + # Update network status. + peer["tcp"].poll() + # Still connected? + if peer["tcp"].get_status() == StreamPeerTCP.STATUS_ERROR: + peer["tcp"].disconnect_from_host() + peer["tcp"] = null + print("Lost peer ", peer["ip"], ":", peer["port"]) + else: + # Data waiting? + if peer["tcp"].get_status() == StreamPeerTCP.STATUS_CONNECTED: + if peer["tcp"].get_available_bytes() > 0: + var data = peer["tcp"].get_var() + peer_received_packet.emit(peer, data["verb"], data["payload"]) + + func clear(): peerArray.clear() -func is_peer_connected(peer): - if is_peer_valid(peer): - if peer["enet"].get_state() == ENetPacketPeer.STATE_CONNECTED: - return true - return false - - -func is_peer_disconnected(peer): - if is_peer_valid(peer): - if peer["enet"].get_state() == ENetPacketPeer.STATE_DISCONNECTED: - return true - return false - - -func is_peer_valid(peer): - if typeof(peer["enet"]) == TYPE_OBJECT: - if peer["enet"] != null: - return true - return false - - func is_running(): return _serverRunning +func send_to_peer(peer, verb: String, payload: Dictionary): + if peer["tcp"] != null: + if peer["tcp"].get_status() == StreamPeerTCP.STATUS_CONNECTED: + var message = {} + message["verb"] = verb + message["payload"] = payload + peer["tcp"].put_var(message) + peer["tcp"].poll() + + func start_server(address, portStart, user, uuid): if !_serverRunning: clear() @@ -136,8 +149,7 @@ func start_server(address, portStart, user, uuid): _userInfo["id"] = _userInfo["ip"].get_slice(".", 3).to_int() # Use last octet for our ID. _userInfo["port"] = _basePort + _userInfo["id"] # Set up our listening port. - _userInfo["enet"] = ENetConnection.new() - _userInfo["enet"].create_host_bound(_userInfo["ip"], _userInfo["port"], 256, 0) + _tcp.listen(_userInfo["port"], _userInfo["ip"]) _serverRunning = true @@ -145,8 +157,13 @@ func stop_server(): if _serverRunning: # Tear down network. _serverRunning = false - _userInfo["enet"].flush() - _userInfo["enet"].destroy() + for peer in peerArray: + if peer["tcp"] != null: + send_to_peer(peer, "online", { "status": false }) + peer["tcp"].disconnect_from_host() + peer["tcp"] = null + print("Disconnected peer ", peer["ip"], ":", peer["port"]) + _tcp.stop() func update(peersFromCPP: Array): @@ -178,34 +195,27 @@ func update(peersFromCPP: Array): if oldPeer["ip"] == peerCPP["ip"]: found = true peerCPP = oldPeer - # Update peer statistics. ***TODO*** These do not set 'changed' and are not refreshed. - if is_peer_connected(peerCPP): - peerCPP["ping"] = peerCPP["enet"].get_statistic(ENetPacketPeer.PEER_ROUND_TRIP_TIME) if !found: # We didn't have them. Add needed records. peerCPP["user"] = "" peerCPP["uuid"] = "" - peerCPP["online"] = true + peerCPP["online"] = false peerCPP["refresh"] = false - peerCPP["ping"] = 0.0 changed = true - # Also create the ENet connection data. + # Also create the TCP connection data. peerCPP["id"] = peerCPP["ip"].get_slice(".", 3).to_int() # Use last octet for our ID. peerCPP["port"] = _basePort + peerCPP["ip"].get_slice(".", 3).to_int() - peerCPP["enet"] = null - # Sometimes the CPP code will return duplicates. Check. - # Also check if we need to redraw anyone. - found = false - for peer in peerArray: - if peer["ip"] == peerCPP["ip"]: - found = true - if peer["refresh"] == true: - peer["refresh"] = false - changed = true + peerCPP["tcp"] = null # Add them to the new list. peerArray.append(peerCPP) + # Check if we need to redraw anyone. + for peer in peerArray: + if peer["refresh"] == true: + peer["refresh"] = false + changed = true + # Sort new array. peerArray.sort_custom(_sort_by_ip) diff --git a/hamncheese/project.godot b/hamncheese/project.godot index 1dc8013..4f10fdb 100644 --- a/hamncheese/project.godot +++ b/hamncheese/project.godot @@ -26,6 +26,7 @@ Process="*res://Scripts/process.gd" Dialog="*res://Scripts/dialog.gd" Edge="*res://Scripts/edge.gd" Peers="*res://Scripts/peers.gd" +Network="*res://Scripts/network.gd" Settings="*res://Scenes/settings.tscn" About="*res://Scenes/about.tscn" Manual="*res://Scenes/manual.tscn"