aboutsummaryrefslogtreecommitdiff
path: root/client/multiplayer.gd
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-06-23 20:05:28 +0200
committermetamuffin <metamuffin@disroot.org>2024-06-23 20:05:28 +0200
commit3885cbfae528608350804f704dba9c82fdbfd027 (patch)
tree384a37820cf43d1868493600a8e0566c78b9ab4a /client/multiplayer.gd
parent93221433e704e1c98cc84c55caefddb85c2d5717 (diff)
downloadhurrycurry-3885cbfae528608350804f704dba9c82fdbfd027.tar
hurrycurry-3885cbfae528608350804f704dba9c82fdbfd027.tar.bz2
hurrycurry-3885cbfae528608350804f704dba9c82fdbfd027.tar.zst
move files around
Diffstat (limited to 'client/multiplayer.gd')
-rw-r--r--client/multiplayer.gd205
1 files changed, 205 insertions, 0 deletions
diff --git a/client/multiplayer.gd b/client/multiplayer.gd
new file mode 100644
index 00000000..534ef663
--- /dev/null
+++ b/client/multiplayer.gd
@@ -0,0 +1,205 @@
+# Undercooked - a game about cooking
+# Copyright 2024 nokoe
+# Copyright 2024 metamuffin
+# Copyright 2024 tpart
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, version 3 of the License only.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+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 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 character = decoded["character"]
+ emit_signal("add_player", id, player_name, pos_to_vec2(pos), character)
+ "remove_player":
+ var id = decoded["id"]
+ emit_signal("remove_player", id)
+ "position":
+ var player = decoded["player"]
+ var pos = decoded["pos"]
+ var rot = decoded["rot"]
+ emit_signal("position", player, pos_to_vec2(pos), rot)
+ "take_item":
+ var tile = pos_to_vec2i(decoded["tile"])
+ var player = decoded["player"]
+ emit_signal("take_item", tile, player)
+ "put_item":
+ var tile = pos_to_vec2i(decoded["tile"])
+ var player_id = decoded["player"]
+ emit_signal("take_item", tile, player_id)
+ "set_active":
+ var tile = pos_to_vec2i(decoded["tile"])
+ var warn = decoded["warn"]
+ var progress = decoded.get("progress")
+ if progress != null:
+ 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"])
+ var item = decoded.get("item")
+ if item != null:
+ emit_signal("set_tile_item", tile, item)
+ else:
+ emit_signal("remove_tile_item", tile)
+ "set_player_item":
+ var player = decoded["player"]
+ var item = decoded.get("item")
+ if item != null:
+ emit_signal("set_player_item", player, decoded["item"])
+ else:
+ emit_signal("remove_player_item", player)
+ "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"]
+ var message = decoded.get("message")
+ if message != null:
+ var item = message.get("item")
+ var text = message.get("text")
+ if item != null:
+ emit_signal("item_message", player, item)
+ elif text != null:
+ emit_signal("text_message", player, text)
+ else:
+ push_error("neither text nor item provided")
+ else:
+ emit_signal("clear_message", player)
+ "error":
+ var message = decoded["message"]
+ push_warning("server error: %s" % message)
+ _:
+ 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.get(str(pos))
+ if t == null: return false
+ else: return tile_collide[t]
+
+func get_tile_interactive(pos: Vector2i) -> bool:
+ var t = tileid_by_pos.get(str(pos))
+ if t == null: return false
+ else: return tile_interact[t]