aboutsummaryrefslogtreecommitdiff
path: root/client/scripts/multiplayer.gd
blob: 18141efa686668c17dd2d2c014a030a5b37ebd04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
extends Node

signal init(player_id: int)
signal update_map(tile: int, pos: Array, neighbors: Array)
signal clear_message(player: int)
signal text_message(player: int, text: String)
signal item_message(player: int, item: int)
signal add_player(player: int, name: String, pos: Vector2, character: int)
signal remove_player(player: int)
signal position(player: int, position: Vector2, rotation: float)
signal take_item(tile: Vector2i, player: int)
signal put_item(tile: Vector2i, player: int)
signal set_tile_item(tile: Vector2i, item: int)
signal remove_tile_item(tile: Vector2i)
signal set_progress(tile: Vector2i, progress: float, warn: bool)
signal set_finished(tile: Vector2i, warn: bool)

var connected := false
var socket := WebSocketPeer.new()

var item_names = []
var tile_names = []
var tile_collide = []
var tile_interact = []
var item_idx_from_name: Dictionary = {}
var player_id = -1

var other_players = {}
var tileid_by_pos: Dictionary = {}

func connectClient(url: String):
	socket.connect_to_url(url)
	connected = true

func _process(_delta):
	if connected:
		socket.poll()
		var state = socket.get_ready_state()
		if state == WebSocketPeer.STATE_OPEN:
			while socket.get_available_packet_count():
				handle_packet(socket.get_packet())
		elif state == WebSocketPeer.STATE_CONNECTING:
			print("connecting")
		elif state == WebSocketPeer.STATE_CLOSING:
			# Keep polling to achieve proper close.
			print("closing")
			pass
		elif state == WebSocketPeer.STATE_CLOSED:
			var code = socket.get_close_code()
			var reason = socket.get_close_reason()
			print("WebSocket closed with code: %d, reason %s. Clean: %s" % [code, reason, code != - 1])

func handle_packet(bytes: PackedByteArray):
	var decoded = decode_packet(bytes)

	if decoded == null:
		return

	var packet_type: String = decoded["type"]
	match packet_type:
		"init":
			player_id = decoded["id"]
			item_names = decoded["data"]["item_names"]
			tile_names = decoded["data"]["tile_names"]
			tile_collide = decoded["data"]["tile_collide"]
			tile_interact = decoded["data"]["tile_interact"]
			for i in range(item_names.size()):
				item_idx_from_name[item_names[i]] = i
			emit_signal("init", player_id)
		"add_player":
			var id = decoded["id"]
			var player_name = decoded["name"]
			var pos = decoded["position"]
			var char = decoded["character"]
			other_players[id] = [player_name, char]
			emit_signal("add_player", id, player_name, pos_to_vec2(pos), char)
		"remove_player":
			var id = decoded["id"]
			other_players.erase(id)
			emit_signal("remove_player", id)
		"position":
			var id = decoded["player"]
			var pos = decoded["pos"]
			var rot = decoded["rot"]
			emit_signal("position", id, pos_to_vec2(pos), rot)
		"take_item":
			var tile = pos_to_vec2i(decoded["tile"])
			var player_id = decoded["player"]
			emit_signal("take_item", tile, player_id)
		"put_item":
			var tile = pos_to_vec2i(decoded["tile"])
			var player_id = decoded["player"]
			emit_signal("take_item", tile, player_id)
		"set_progress":
			var tile = pos_to_vec2i(decoded["tile"])
			var warn = decoded["warn"]
			if decoded.has("progress"):
				emit_signal("set_progress", tile, decoded["progress"], warn)
			else:
				emit_signal("set_finished", tile, warn)
		"set_tile_item":
			var tile = pos_to_vec2i(decoded["tile"])
			if decoded.has("item") && decoded["item"] != null:
				emit_signal("set_tile_item", tile, decoded["item"])
			else:
				emit_signal("remove_tile_name", tile)
		"update_map":
			var tile: int = decoded["tile"]
			var pos: Array = decoded["pos"]
			var neighbors: Array = decoded["neighbors"]
			tileid_by_pos[str(Vector2i(pos[0],pos[1]))] = tile
			emit_signal("update_map", pos, tile_names[tile], neighbors)
		"communicate":
			var player = decoded["player"]
			if decoded.has("message"):
				var message: Dictionary = decoded["message"]
				if message.has("item"):
					emit_signal("item_message", player, message["item"])
				else:
					emit_signal("text_message", player, message["text"])
			else:
				emit_signal("clear_message", player)
		_:
			push_error("Unrecognized packet type: %s" % packet_type)

func send_join(player_name: String, character: int):
	send_packet({
		"type": "join",
		"name": player_name,
		"character": character
	})

func send_position(pos: Vector2, rotation: float):
	send_packet({
		"type": "position",
		"pos": [pos.x, pos.y],
		"rot": rotation
	})

func send_interact(pos: Vector2i, edge: bool):
	send_packet({
		"type": "interact",
		"pos": [pos.x, pos.y],
		"edge": edge
	})

func send_packet(packet):
	var json = JSON.stringify(packet)
	socket.send_text(json)

func decode_packet(bytes: PackedByteArray):
	var json = JSON.new()
	var in_str = bytes.get_string_from_utf8()
	var error = json.parse(in_str)
	if error == OK:
		return json.data
	else:
		print("Decode of packet failed: %s in %s" % [json.get_error_message(), in_str])
		return null

func pos_to_vec2(pos: Array) -> Vector2:
	return Vector2(pos[0], pos[1])

func pos_to_vec2i(pos: Array) -> Vector2i:
	return Vector2i(pos[0], pos[1])

func get_tile_collision(pos: Vector2i) -> bool:
	var t = tileid_by_pos[str(pos)]
	if t == null: return false
	else: return tile_collide[t]