Current section
Files
Jump to
Current section
Files
priv/templates/libow4.mustache
extends Node
{{#preloads}}
{{.}}
{{/preloads}}
var _enet_peer = ENetMultiplayerPeer.new()
var _ws_peer = WebSocketPeer.new()
var _ws_connected = false
@export var session: Dictionary
@export var rejoin_token: PackedByteArray
var debug = false
var mode
###########################################################################
# Constants
###########################################################################
enum transport_mode {
WEBSOCKET,
ENET
}
# These are merely aliases for convenience. We should not leak Protobuf
# details to the consumer of the library
{{#constants}}
{{.}}
{{/constants}}
###########################################################################
# Signals
###########################################################################
signal server_connected()
signal server_disconnected()
{{#signals}}
{{.}}
{{/signals}}
###########################################################################
# Prefixes
###########################################################################
# Prefixes determine how to route packages to the correct protobuf library
const Prefix = {
{{#prefixes}}
{{.}}
{{/prefixes}}
}
###########################################################################
# Router
###########################################################################
func route(packet):
var opcode = Array(packet.slice(0,2)) # Is this costly?
var payload = []
if packet.size() > 2:
payload = packet.slice(2)
match opcode:
{{#router}}
{{.}}
{{/router}}
_:
print("[WARNING] Unknown opcode from the server:" + str(opcode))
###########################################################################
# Payload unmarshalling (server packets)
###########################################################################
# Submsgs
{{#submsgs}}
{{.}}
{{/submsgs}}
# Unmarshall
{{#unmarshall}}
{{.}}
{{/unmarshall}}
###########################################################################
# Payload marshalling (client packets)
###########################################################################
# Marshall submsgs
{{#marshall_submsgs}}
{{.}}
{{/marshall_submsgs}}
# Marshall
{{#marshall}}
{{.}}
{{/marshall}}
############################################################################
# Various other utility and initialization functions
############################################################################
func _ready():
# Automatically reply to beacons
server_session_beacon.connect(self._on_session_beacon)
func enet_connect(ip: String, port: int):
print("[INFO] Connecting via ENet to ", ip)
var _err = _enet_peer.create_client(ip, port, 4)
mode = transport_mode.ENET
# Set mode to ZLIB
_enet_peer.host.compress(ENetConnection.COMPRESS_ZLIB)
func enet_disconnect():
for peer in _enet_peer.host.get_peers():
print("Peer: " + str(peer))
peer.peer_disconnect()
_enet_peer.close()
mode = null
emit_signal("server_disconnected")
# Take the host and whether or not its a TLS conncetion
func ws_connect(address: String, port: int = 4433):
var url = "ws://" + address + ":" + str(port) + "/ws"
print("[INFO] Connecting via WebSocket to ", url)
_websocket_connect(url)
func ws_disconnect():
_websocket_close()
mode = null
func wss_connect(address: String, port: int = 4434):
var url = "wss://" + address + ":" + str(port) + "/ws"
print("[INFO] Connecting via WebSocketSecure to ", url)
_websocket_connect(url)
func wss_disconnect():
_websocket_close()
func _websocket_connect(url):
_ws_peer.connect_to_url(url)
mode = transport_mode.WEBSOCKET
func _websocket_close():
_ws_peer.close()
func _send_message(payload, opcode, qos, channel):
# Create a new packet starting with opcode, append the message if it exists,
# then send it across the websocket or ENet connection.
# Set the peer mode
var peer
if mode == transport_mode.WEBSOCKET:
var packet = [] + opcode
peer = _ws_peer
# Construct the packet
if payload.is_empty() != true:
# Append the payload to the packet if it's nonempty
packet.append_array(payload)
peer.send(packet)
elif mode == transport_mode.ENET:
var packet = [] + opcode # TODO: Workaround
peer = _enet_peer
for p in peer.host.get_peers():
# TODO: Thread channel and packet type through
if payload.is_empty() != true:
packet.append_array(payload)
var flag
match qos:
"reliable":
flag = ENetPacketPeer.FLAG_RELIABLE
"unreliable":
flag = ENetPacketPeer.FLAG_UNRELIABLE_FRAGMENT
"unsequenced":
flag = ENetPacketPeer.FLAG_UNSEQUENCED
p.send(channel, packet, flag)
func _process(_delta):
if mode == transport_mode.WEBSOCKET:
_ws_peer.poll()
var state = _ws_peer.get_ready_state()
if state == WebSocketPeer.STATE_OPEN:
if _ws_connected == false:
emit_signal("server_connected")
_ws_connected = true
while _ws_peer.get_available_packet_count():
var packet = _ws_peer.get_packet()
route(packet)
elif state == WebSocketPeer.STATE_CLOSING:
# Keep polling to achieve proper close.
pass
elif state == WebSocketPeer.STATE_CLOSED:
_ws_connected = false
emit_signal("server_disconnected")
elif mode == transport_mode.ENET:
var p = _enet_peer.host.service() # Check for packets
if p[0] == ENetConnection.EVENT_CONNECT:
emit_signal("server_connected")
elif p[0] == ENetConnection.EVENT_DISCONNECT:
emit_signal("server_disconnected")
elif p[0] == ENetConnection.EVENT_RECEIVE:
var packet = p[1].get_packet()
route(packet)
############################################################################
# Signal Handlers
############################################################################
func _closed(was_clean = false):
# was_clean will tell you if the disconnection was correctly notified
# by the remote peer before closing the socket.
print("Closed, clean: ", was_clean)
set_process(false)
func _connected(proto = ""):
# This is called on connection, "proto" will be the selected WebSocket
# sub-protocol (which is optional)
print("Connected with protocol: ", proto)
##func _on_data():
## var packet = _ws_client.get_peer(1).get_packet()
## route(packet)
func _on_session_beacon(id):
# Used for latency measurements
session_ping(id)