Problem Using MultiplayerPeerExtension

Godot Version

4.3

Question

My goal is to wrap an EnetMultiplayerPeer inside of a MultiplayerPeerExtension to manipulate packet delay and loss.

My problem is after wrapping the enet class my multiplayer example stops working without error. I get confirmation that server and client are created successfully, but none of the callbacks for server/peer connected fire.

I’m using gdb to investigate but the process is a little slow as im not sure where the problem is. I was wondering if someone else has successfully done this already in 4.3?

I dont see any issues on github related to this, so im hoping its a me issue.

code

The code is just a pass-through implementation that logs the behavior and results. Some print statements are commented out or conditionally printed to reduce spam in the console log.

EnetMultiplayerPeerExtension
extends MultiplayerPeerExtension

class_name ENetMultiplayerPeerExtension

var enet : = ENetMultiplayerPeer.new()
var type : String = "Unkown"

### NOTE: MultiplayerPeer 
###
func _close() -> void:
	print("%s: close" % [type])
	enet.close()

func _disconnect_peer(p_peer: int, p_force: bool) -> void:
	print("%s: disconnect_peer %d force %s" % [type, p_peer, p_force])
	enet.disconnect_peer(p_peer, p_force)

func _get_available_packet_count() -> int:
	var pc : = enet.get_available_packet_count()
	if pc > 0:
		print("%s: get_available_packet_count: %d" % [type, enet.get_available_packet_count()])
	return enet.get_available_packet_count()

func _get_connection_status() -> MultiplayerPeer.ConnectionStatus:
	var status : String = ""
	match (enet.get_connection_status()):
		MultiplayerPeer.ConnectionStatus.CONNECTION_CONNECTED:
			status = "CONNECTION_CONNECTED"
		MultiplayerPeer.ConnectionStatus.CONNECTION_CONNECTING:
			status = "CONNECTION_CONNECTING"
		MultiplayerPeer.ConnectionStatus.CONNECTION_DISCONNECTED:
			status = "CONNECTION_DISCONNECTED"
	#print("%s: get_connection_status: %s" % [type, status])
	return enet.get_connection_status()

func _get_max_packet_size() -> int:
	print("%s: get_max_packet_size %d " % [type, enet.get_max_packet_size()])
	return enet.get_max_packet_size() #does this exist?

func _get_packet_channel() -> int:
	print("%s: get_packet_channel: %d " % [type, enet.get_packet_channel()])
	return enet.get_packet_channel()

func _get_packet_mode() -> MultiplayerPeer.TransferMode:
	var mode : String = ""
	match (enet.get_packet_mode()):
		MultiplayerPeer.TransferMode.TRANSFER_MODE_RELIABLE:
			mode = "TRANSFER_MODE_RELIABLE"
		MultiplayerPeer.TransferMode.TRANSFER_MODE_UNRELIABLE:
			mode = "TRANSFER_MODE_UNRELIABLE"
		MultiplayerPeer.TransferMode.TRANSFER_MODE_UNRELIABLE_ORDERED:
			mode = "TRANSFER_MODE_UNRELIABLE_ORDERED"
	print("%s: get_packet_mode: %s" % [type, mode])
	return enet.get_packet_mode()

func _get_packet_peer() -> int:
	print("%s: get_packet_peer: %d" % [type, enet.get_packet_peer()])
	return enet.get_packet_peer()

# gdscript only as _get_packet() uses native parameters
func _get_packet_script() -> PackedByteArray:
	print("%s: get_packet size: %d" % [type, enet.get_packet().size()])
	return enet.get_packet()

func _get_transfer_channel() -> int:
	print("%s: get_transfer_channel: %d " % [type, enet.get_transfer_channel()])
	return enet.get_transfer_channel()

func _get_transfer_mode() -> MultiplayerPeer.TransferMode:
	var mode : String = ""
	match (enet.get_packet_mode()):
		MultiplayerPeer.TransferMode.TRANSFER_MODE_RELIABLE:
			mode = "TRANSFER_MODE_RELIABLE"
		MultiplayerPeer.TransferMode.TRANSFER_MODE_UNRELIABLE:
			mode = "TRANSFER_MODE_UNRELIABLE"
		MultiplayerPeer.TransferMode.TRANSFER_MODE_UNRELIABLE_ORDERED:
			mode = "TRANSFER_MODE_UNRELIABLE_ORDERED"
	print("%s: get_transfer_mode: %s" % [type, mode])
	return enet.get_transfer_mode()

func _get_unique_id() -> int:
	print("%s: get_unique_id: %d " % [type, enet.get_unique_id()])
	return enet.get_unique_id()

func _is_refusing_new_connections() -> bool:
	print("%s: is_refusing_new_connections %s" % [type ,enet.is_refusing_new_connections()])
	return enet.is_refusing_new_connections()

func _is_server() -> bool:
	print("%s: is_server %s" % [type, enet.is_server()])
	return enet.is_server()

func _is_server_relay_supported() -> bool:
	print("%s: is_server_relay_supported %s" % [type, enet.is_server_relay_supported()])
	return enet.is_server_relay_supported()

func _poll() -> void:
	#print("%s: poll"% [type])
	enet.poll()

# gdscript only as _put_packet() uses native parameters
func _put_packet_script(p_buffer: PackedByteArray) -> Error:
	print("%s: put_packet size: %d "% [type, p_buffer.size()])
	return enet.put_packet(p_buffer)

func _set_refuse_new_connections(p_enable: bool) -> void:
	print("%s: set_refuse_new_connections %s" % [type, p_enable])
	enet.set_refuse_new_connections(p_enable)

func _set_target_peer(p_peer: int) -> void:
	print("%s: set_target_peer: %d" % [type, p_peer])
	enet.set_target_peer(p_peer)

func _set_transfer_channel(p_channel: int) -> void:
	print("%s: set_transfer_channel: %d"% [type, p_channel])
	enet.set_transfer_channel(p_channel)

func _set_transfer_mode(p_mode: MultiplayerPeer.TransferMode) -> void:
	var mode : String = ""
	match (p_mode):
		MultiplayerPeer.TransferMode.TRANSFER_MODE_RELIABLE:
			mode = "TRANSFER_MODE_RELIABLE"
		MultiplayerPeer.TransferMode.TRANSFER_MODE_UNRELIABLE:
			mode = "TRANSFER_MODE_UNRELIABLE"
		MultiplayerPeer.TransferMode.TRANSFER_MODE_UNRELIABLE_ORDERED:
			mode = "TRANSFER_MODE_UNRELIABLE_ORDERED"
	print("%s: set_transfer_mode: %s" % [type, mode])
	enet.set_transfer_mode(p_mode)

### NOTE: ENet functions
###
func add_mesh_peer(peer_id: int, host: ENetConnection) -> Error:
	return enet.add_mesh_peer(peer_id, host)

func create_client(address: String, port: int, channel_count: int = 0, in_bandwidth: int = 0, out_bandwidth: int = 0, local_port: int = 0) -> Error:
	type = "Client"
	var err = enet.create_client(address, port, channel_count, in_bandwidth, out_bandwidth, local_port)
	print("Create client: ", err)
	return err

func create_mesh(unique_id: int) -> Error:
	return enet.create_mesh(unique_id)

func create_server(port: int, max_clients: int = 32, max_channels: int = 0, in_bandwidth: int = 0, out_bandwidth: int = 0) -> Error:
	type = "Server"
	var err = enet.create_server(port, max_clients, max_channels, in_bandwidth, out_bandwidth)
	print("Create Server: ",err)
	return err

func get_peer(id: int) -> ENetPacketPeer:
	return enet.get_peer(id)

func set_bind_ip(ip: String) -> void:
	enet.set_bind_ip(ip)

1 Like

Silly me, I forgot to connect the signals peer_connected and peer_disconnected of the enet instance. I fixed some other issues but here is the fixed code

Fixed Code
extends MultiplayerPeerExtension

class_name ENetMultiplayerPeerExtension

var enet : = ENetMultiplayerPeer.new()
var type : String = "Unkown"
var logs_enabled : bool = false

func _init() -> void:
	enet.peer_connected.connect(func(id:int):peer_connected.emit(id))
	enet.peer_disconnected.connect(func(id:int):peer_disconnected.emit(id))

### NOTE: MultiplayerPeer 
###
func _close() -> void:
	print_utl("%s: close", [type])
	enet.close()

func _disconnect_peer(p_peer: int, p_force: bool) -> void:
	print_utl("%s: disconnect_peer %d force %s", [type, p_peer, p_force])
	enet.disconnect_peer(p_peer, p_force)

func _get_available_packet_count() -> int:
	var pc : = enet.get_available_packet_count()
	if pc > 0:
		print_utl("%s: get_available_packet_count: %d", [type, pc])
	return pc

func _get_connection_status() -> MultiplayerPeer.ConnectionStatus:
	var status:= enet.get_connection_status()
	print_utl("%s: get_connection_status: %s", [type, get_enum_str(status)])
	return status

func _get_max_packet_size() -> int:
	var packet_size : int = enet.get_max_packet_size()
	print_utl("%s: get_max_packet_size %d ", [type, packet_size])
	return packet_size

func _get_packet_channel() -> int:
	var channel : int = enet.get_packet_channel()
	print_utl("%s: get_packet_channel: %d ", [type, channel])
	return channel

func _get_packet_mode() -> MultiplayerPeer.TransferMode:
	var mode := enet.get_packet_mode()
	print_utl("%s: get_packet_mode: %s", [type, get_enum_str(mode)])
	return mode

func _get_packet_peer() -> int:
	var peer : int = enet.get_packet_peer()
	print_utl("%s: get_packet_peer: %d", [type, peer])
	return peer

# gdscript only as _get_packet() uses native parameters
func _get_packet_script() -> PackedByteArray:
	var packet:PackedByteArray = enet.get_packet()
	print_utl("%s: get_packet size: %d", [type, packet.size()])
	return packet

func _get_transfer_channel() -> int:
	var channel:int = enet.get_transfer_channel()
	print_utl("%s: get_transfer_channel: %d ", [type, channel])
	return channel

func _get_transfer_mode() -> MultiplayerPeer.TransferMode:
	var mode : = enet.get_packet_mode()
	print_utl("%s: get_transfer_mode: %s", [type, get_enum_str(mode)])
	return mode

func _get_unique_id() -> int:
	var id :int = enet.get_unique_id()
	print_utl("%s: get_unique_id: %d ", [type, id])
	return id

func _is_refusing_new_connections() -> bool:
	print_utl("%s: is_refusing_new_connections %s", [type ,enet.is_refusing_new_connections()])
	return enet.is_refusing_new_connections()

func _is_server() -> bool:
	print_utl("%s: is_server %s", [type, enet.is_server()])
	return enet.is_server()

func _is_server_relay_supported() -> bool:
	print_utl("%s: is_server_relay_supported %s", [type, enet.is_server_relay_supported()])
	return enet.is_server_relay_supported()

func _poll() -> void:
	#print_utl("%s: poll"% [type])
	enet.poll()

# gdscript only as _put_packet() uses native parameters
func _put_packet_script(p_buffer: PackedByteArray) -> Error:
	print_utl("%s: put_packet size: %d ", [type, p_buffer.size()])
	return enet.put_packet(p_buffer)

func _set_refuse_new_connections(p_enable: bool) -> void:
	print_utl("%s: set_refuse_new_connections %s", [type, p_enable])
	enet.set_refuse_new_connections(p_enable)

func _set_target_peer(p_peer: int) -> void:
	print_utl("%s: set_target_peer: %d", [type, p_peer])
	enet.set_target_peer(p_peer)

func _set_transfer_channel(p_channel: int) -> void:
	print_utl("%s: set_transfer_channel: %d", [type, p_channel])
	enet.set_transfer_channel(p_channel)

func _set_transfer_mode(p_mode: MultiplayerPeer.TransferMode) -> void:
	var mode_str : String = get_enum_str(p_mode)
	print_utl("%s: set_transfer_mode: %s", [type, mode_str])
	enet.set_transfer_mode(p_mode)

### NOTE: ENet functions
###
func add_mesh_peer(peer_id: int, host: ENetConnection) -> Error:
	return enet.add_mesh_peer(peer_id, host)

func create_client(address: String, port: int, channel_count: int = 0, in_bandwidth: int = 0, out_bandwidth: int = 0, local_port: int = 0) -> Error:
	type = "Client"
	var err = enet.create_client(address, port, channel_count, in_bandwidth, out_bandwidth, local_port)
	print_utl("Create client: %i", [err])
	return err

func create_mesh(unique_id: int) -> Error:
	return enet.create_mesh(unique_id)

func create_server(port: int, max_clients: int = 32, max_channels: int = 0, in_bandwidth: int = 0, out_bandwidth: int = 0) -> Error:
	type = "Server"
	var err = enet.create_server(port, max_clients, max_channels, in_bandwidth, out_bandwidth)
	print_utl("Create Server: %i", [err])
	return err

func get_peer(id: int) -> ENetPacketPeer:
	return enet.get_peer(id)

func set_bind_ip(ip: String) -> void:
	enet.set_bind_ip(ip)

## NOTE: utility
##

func print_utl(msg:String, args:Array):
	if logs_enabled :
		print(msg % args)

func get_enum_str(value:int) -> String:
	var value_str : String = ""
	match (value):
		MultiplayerPeer.TransferMode.TRANSFER_MODE_RELIABLE:
			value_str = "TRANSFER_MODE_RELIABLE"
		MultiplayerPeer.TransferMode.TRANSFER_MODE_UNRELIABLE:
			value_str = "TRANSFER_MODE_UNRELIABLE"
		MultiplayerPeer.TransferMode.TRANSFER_MODE_UNRELIABLE_ORDERED:
			value_str = "TRANSFER_MODE_UNRELIABLE_ORDERED"
		MultiplayerPeer.ConnectionStatus.CONNECTION_CONNECTED:
			value_str = "CONNECTION_CONNECTED"
		MultiplayerPeer.ConnectionStatus.CONNECTION_CONNECTING:
			value_str = "CONNECTION_CONNECTING"
		MultiplayerPeer.ConnectionStatus.CONNECTION_DISCONNECTED:
			value_str = "CONNECTION_DISCONNECTED"
	return value_str

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.