diff --git a/Actors/Objects/Computer/Computer.tscn b/Actors/Objects/Computer/Computer.tscn index 5b96086..abd2e91 100644 --- a/Actors/Objects/Computer/Computer.tscn +++ b/Actors/Objects/Computer/Computer.tscn @@ -185,6 +185,7 @@ rect_scale = Vector2( 0.5, 0.5 ) [node name="ActivationRange" type="Area2D" parent="."] visible = false +input_pickable = false script = ExtResource( 6 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="ActivationRange"] diff --git a/Actors/Objects/Door/Door.tscn b/Actors/Objects/Door/Door.tscn index b572aae..32fa906 100644 --- a/Actors/Objects/Door/Door.tscn +++ b/Actors/Objects/Door/Door.tscn @@ -66,6 +66,7 @@ one_shot = true [node name="ActivationRange" type="Area2D" parent="."] visible = false +input_pickable = false script = ExtResource( 3 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="ActivationRange"] @@ -73,6 +74,7 @@ position = Vector2( 16, 16 ) shape = SubResource( 8 ) [node name="CloseRange" type="Area2D" parent="."] +input_pickable = false script = ExtResource( 3 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="CloseRange"] diff --git a/Actors/Objects/Engine/Engine.gd b/Actors/Objects/Engine/Engine.gd index b42d3dd..1d5b082 100644 --- a/Actors/Objects/Engine/Engine.gd +++ b/Actors/Objects/Engine/Engine.gd @@ -52,7 +52,7 @@ func refresh_sprite() -> void: $Light2D.rotation = rot $ActivationRange.rotation = rot -func _physics_process(delta: float) -> void: +func _physics_process(_delta: float) -> void: if Engine.editor_hint: return manager.power_usage = max(1e-3, MAX_USAGE * strength) diff --git a/Actors/Objects/Engine/Engine.tscn b/Actors/Objects/Engine/Engine.tscn index e86d425..40d1dfe 100644 --- a/Actors/Objects/Engine/Engine.tscn +++ b/Actors/Objects/Engine/Engine.tscn @@ -14,7 +14,6 @@ extents = Vector2( 72, 72 ) [node name="Engine" type="StaticBody2D"] script = ExtResource( 2 ) -max_force = 0.05 [node name="CollisionShape2D" type="CollisionShape2D" parent="."] position = Vector2( 48, 48 ) @@ -36,6 +35,7 @@ energy = 0.002 [node name="ActivationRange" type="Area2D" parent="."] visible = false +input_pickable = false script = ExtResource( 1 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="ActivationRange"] diff --git a/Actors/Objects/Lightbulb/Lightbulb.tscn b/Actors/Objects/Lightbulb/Lightbulb.tscn index 25b0958..9554049 100644 --- a/Actors/Objects/Lightbulb/Lightbulb.tscn +++ b/Actors/Objects/Lightbulb/Lightbulb.tscn @@ -38,6 +38,7 @@ __meta__ = { [node name="ActivationRange" type="Area2D" parent="."] visible = false +input_pickable = false script = ExtResource( 4 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="ActivationRange"] diff --git a/Actors/Objects/PowerStorage/PowerStorage.tscn b/Actors/Objects/PowerStorage/PowerStorage.tscn index c231cd5..dcf4d99 100644 --- a/Actors/Objects/PowerStorage/PowerStorage.tscn +++ b/Actors/Objects/PowerStorage/PowerStorage.tscn @@ -97,6 +97,7 @@ rect_scale = Vector2( 0.5, 0.5 ) [node name="ActivationRange" type="Area2D" parent="."] visible = false position = Vector2( 16, 16 ) +input_pickable = false script = ExtResource( 3 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="ActivationRange"] diff --git a/Actors/Objects/Scanner/Scanner.gd b/Actors/Objects/Scanner/Scanner.gd index 67d30bd..60d70df 100644 --- a/Actors/Objects/Scanner/Scanner.gd +++ b/Actors/Objects/Scanner/Scanner.gd @@ -5,5 +5,5 @@ class_name GameObjectScanner func serialize(): return {} -func deserialize(data): +func deserialize(_data): pass diff --git a/Actors/Player/Player.gd b/Actors/Player/Player.gd index 776ecb2..4d9ae31 100644 --- a/Actors/Player/Player.gd +++ b/Actors/Player/Player.gd @@ -100,5 +100,5 @@ func draw_circle_arc_poly(center, radius, angle_from, angle_to, color): points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius) draw_polygon(points_arc, colors) -func hear(event): +func hear(_event): pass diff --git a/Actors/Player/Player.tscn b/Actors/Player/Player.tscn index 4d3425d..a1c50c9 100644 --- a/Actors/Player/Player.tscn +++ b/Actors/Player/Player.tscn @@ -24,7 +24,7 @@ position = Vector2( 0, -3 ) shape = SubResource( 1 ) [node name="Earing" type="Area2D" parent="."] -monitorable = false +input_pickable = false collision_layer = 32 collision_mask = 32 diff --git a/Actors/Systems/Area/AreaProbe.gd b/Actors/Systems/Area/AreaProbe.gd index 68205bf..81bb985 100644 --- a/Actors/Systems/Area/AreaProbe.gd +++ b/Actors/Systems/Area/AreaProbe.gd @@ -111,3 +111,26 @@ func _draw(): func _area_moved(): scout() update() + +func serialize(): + var subareas = {} + for child in get_children(): + subareas[child.name] = { + "transform": child.transform + } + return { + "name": area_name, + "wall_path": wall_tilemap, + "base_path": base_tilemap, + "subareas": subareas + } + +func deserialize(data): + for subarea in data.subareas: + var node = Node2D.new() + node.name = subarea + node.transform = data.subareas[subarea].transform + add_child(node) + area_name = data.name + wall_tilemap = data.wall_path + base_tilemap = data.base_path diff --git a/Actors/Systems/Electricity/ElectricProbe.tscn b/Actors/Systems/Electricity/ElectricProbe.tscn index 60358cd..6d20133 100644 --- a/Actors/Systems/Electricity/ElectricProbe.tscn +++ b/Actors/Systems/Electricity/ElectricProbe.tscn @@ -14,6 +14,7 @@ a = Vector2( -16, 16 ) b = Vector2( 48, 16 ) [node name="ElProbe" type="Area2D"] +input_pickable = false collision_layer = 4 collision_mask = 4 script = ExtResource( 1 ) diff --git a/Classes/Coordinates.gd b/Classes/Coordinates.gd index 97bc2ec..9206c0e 100644 --- a/Classes/Coordinates.gd +++ b/Classes/Coordinates.gd @@ -21,7 +21,8 @@ static func to_letter(num: int) -> String: return "Α" elif num < 0: letters = "αβγδεζηθικλμνξοπρστυφχψω" - num = abs(num) + if num < 0: + num = -num var out = "" var base = letters.length() while num > 0: diff --git a/Classes/ResourceQueue.gd b/Classes/ResourceQueue.gd index b88c58c..15736ea 100644 --- a/Classes/ResourceQueue.gd +++ b/Classes/ResourceQueue.gd @@ -4,7 +4,7 @@ var thread var mutex var sem -var gotm_mode = false +var threaded = true var time_max = 100 # Milliseconds. var queue = [] @@ -13,19 +13,15 @@ var pending = {} func _lock(_caller): mutex.lock() - func _unlock(_caller): mutex.unlock() - func _post(_caller): sem.post() - func _wait(_caller): sem.wait() - func queue_resource(path, p_in_front = false): _lock("queue_resource") if path in pending: @@ -48,7 +44,6 @@ func queue_resource(path, p_in_front = false): _unlock("queue_resource") return - func cancel_resource(path): _lock("cancel_resource") if path in pending: @@ -57,9 +52,8 @@ func cancel_resource(path): pending.erase(path) _unlock("cancel_resource") - func get_progress(path): - if gotm_mode: + if not threaded: return 1.0 _lock("get_progress") var ret = -1 @@ -71,9 +65,8 @@ func get_progress(path): _unlock("get_progress") return ret - func is_ready(path): - if gotm_mode: + if not threaded: return true var ret _lock("is_ready") @@ -84,9 +77,8 @@ func is_ready(path): _unlock("is_ready") return ret - func _wait_for_resource(res, path): - if gotm_mode: + if not threaded: return get_resource(path) _unlock("wait_for_resource") while true: @@ -97,9 +89,8 @@ func _wait_for_resource(res, path): return pending[path] _unlock("wait_for_resource") - func get_resource(path): - if gotm_mode: + if not threaded: return load(path) _lock("get_resource") if path in pending: @@ -123,7 +114,6 @@ func get_resource(path): _unlock("return") return ResourceLoader.load(path) - func thread_process(): _wait("thread_process") _lock("process") @@ -143,16 +133,15 @@ func thread_process(): queue.erase(res) _unlock("process") - func thread_func(_u): while true: thread_process() - -func start(gotm: bool): - gotm_mode = gotm - if not gotm: - mutex = Mutex.new() - sem = Semaphore.new() - thread = Thread.new() - thread.start(self, "thread_func", 0) +func start(use_threads: bool): + threaded = use_threads + if not threaded: + return + mutex = Mutex.new() + sem = Semaphore.new() + thread = Thread.new() + thread.start(self, "thread_func", 0) diff --git a/Scenes/EditorOnly/TestOdyssey.tscn b/Scenes/EditorOnly/TestOdyssey.tscn index dedda56..628e19f 100644 --- a/Scenes/EditorOnly/TestOdyssey.tscn +++ b/Scenes/EditorOnly/TestOdyssey.tscn @@ -4,7 +4,6 @@ script/source = "extends Node func _ready(): - $\"/root/Multiplayer\".gotm_mode = true # Faster startup $\"/root/Multiplayer\".host() " diff --git a/Scenes/Game.gd b/Scenes/Game.gd index ba427d7..7e651d1 100644 --- a/Scenes/Game.gd +++ b/Scenes/Game.gd @@ -14,7 +14,6 @@ var writing = false func _ready() -> void: randomize() - ui.connect("command", world, "process_command") if netgame.hosting: world.load_map(netgame.get_current_map()) world.map.current_ship_position = Vector2(randf() * 1e4, randf() * 1e4) @@ -58,11 +57,14 @@ master func broadcast_zone(message: String, origin: Vector2, radius: float) -> v var shape = CircleShape2D.new() shape.radius = radius var query = Physics2DShapeQueryParameters.new() + query.collide_with_areas = true + query.collide_with_bodies = false query.collision_layer = 32 - query.transform = Transform(world.transform.translated(origin)) + query.transform.origin = origin query.set_shape(shape) var res = physics.intersect_shape(query, 100) - print(res) + for col in res: + rpc_id(col.collider.get_network_master(), "add_log", message) master func broadcast(message: String) -> void: rpc("add_log", message) diff --git a/Scenes/Global/Multiplayer.gd b/Scenes/Global/Multiplayer.gd index db0c9de..6d4d8af 100644 --- a/Scenes/Global/Multiplayer.gd +++ b/Scenes/Global/Multiplayer.gd @@ -14,7 +14,7 @@ const SYSTEMS_UPDATE_INTERVAL = 10 # Master server data const MASTER_SERVER_ADDR = "fgms.zyg.ovh" const MASTER_SERVER_UDP_PORT = 9434 -const MS_GAME_CODE = "odyssey-0-a1" +const MS_GAME_CODE = "odyssey-0-a2" const GOTM_OVERRIDE = false # Master server entry @@ -22,7 +22,6 @@ var ms_active = false var ms_key = "" var server_name = "" -onready var gotm_mode = Gotm.is_live() or GOTM_OVERRIDE var hosting = false export var player_name = "" @@ -34,8 +33,6 @@ onready var scene_manager = $"/root/SceneManager" func _ready(): player_name = "tider-" + str(randi() % 1000) - if gotm_mode: - Gotm.connect("lobby_changed", self, "_lobby_changed") func bind_events(): get_tree().connect("network_peer_connected", self, "_player_connected") @@ -76,22 +73,17 @@ func host(): yield(get_tree().create_timer(0.3), "timeout") # Run port forwarding/nat punchthrough if the platform doesn't do it already - if not gotm_mode: - print("Running UPNP magicks") - if discover_upnp() == UPNP.UPNP_RESULT_SUCCESS: - print("UPNP mapping added") - else: - push_warning("UPNP magicks fail, punching NAT in the face") - yield(punch_nat(), "completed") + print("Running UPNP magicks") + if discover_upnp() == UPNP.UPNP_RESULT_SUCCESS: + print("UPNP mapping added") + else: + push_warning("UPNP magicks fail, punching NAT in the face") + yield(punch_nat(), "completed") server_name = player_name + "'s server" player_info[1] = { "name": player_name } round_info = { "map": "odyssey" } - if gotm_mode: - # Add to master server before hosting (in GOTM mode) - create_ms_entry() - bind_events() var peer = NetworkedMultiplayerENet.new() peer.compression_mode = NetworkedMultiplayerENet.COMPRESS_FASTLZ @@ -113,9 +105,8 @@ func host(): "res://Scenes/Maps/odyssey.tscn" ]) - if not gotm_mode: - # Add to master server after hosting - create_ms_entry() + # Add to master server after hosting + create_ms_entry() func join(server): scene_manager.enter_loader() @@ -126,13 +117,9 @@ func join(server): bind_events() var peer = NetworkedMultiplayerENet.new() + peer.compression_mode = NetworkedMultiplayerENet.COMPRESS_FASTLZ - var addr = null - if gotm_mode: - var success = yield(server.join(), "completed") - addr = Gotm.lobby.host.address - else: - addr = server.address + var addr = server.address peer.create_client(addr, SERVER_PORT) get_tree().network_peer = peer @@ -193,20 +180,15 @@ func _ms_request(endpoint: String, data): push_error("An error occurred in the HTTP request.") func ms_get_entries(): - if gotm_mode: - var fetch = GotmLobbyFetch.new() - var lobbies = yield(fetch.first(), "completed") - emit_signal("ms_updated", "list_games", lobbies) - else: - var http_request = HTTPRequest.new() - add_child(http_request) - http_request.connect("request_completed", self, "_ms_response", ["list_games"]) - var error = http_request.request( - "https://" + MASTER_SERVER_ADDR + "/" + MS_GAME_CODE, - ["Content-Type: application/json"], - true, HTTPClient.METHOD_GET) - if error != OK: - push_error("An error occurred in the HTTP request.") + var http_request = HTTPRequest.new() + add_child(http_request) + http_request.connect("request_completed", self, "_ms_response", ["list_games"]) + var error = http_request.request( + "https://" + MASTER_SERVER_ADDR + "/" + MS_GAME_CODE, + ["Content-Type: application/json"], + true, HTTPClient.METHOD_GET) + if error != OK: + push_error("An error occurred in the HTTP request.") func get_game_data(): return { @@ -217,28 +199,17 @@ func get_game_data(): } func create_ms_entry(): - if gotm_mode: - Gotm.host_lobby(true) - Gotm.lobby.hidden = false - else: - _ms_request("new", { - "game_id": MS_GAME_CODE, - "data": get_game_data() - }) - update_ms_entry() + _ms_request("new", { + "game_id": MS_GAME_CODE, + "data": get_game_data() + }) func update_ms_entry(): - if gotm_mode: - var data = get_game_data() - Gotm.lobby.name = data.name - for key in data: - Gotm.lobby.set_property(key, data[key]) - else: - if ms_active: - _ms_request("update", { - "key": ms_key, - "data": get_game_data() - }) + if ms_active: + _ms_request("update", { + "key": ms_key, + "data": get_game_data() + }) var time_left = 30 func _process(delta): @@ -276,6 +247,3 @@ func get_current_map(): return GameWorld.Map.RUNTIME _: return GameWorld.Map.EMPTY - -func _lobby_changed(): - print("Lobby changed ", Gotm.lobby) diff --git a/Scenes/Global/SceneManager.gd b/Scenes/Global/SceneManager.gd index 916c4a0..4babf9d 100644 --- a/Scenes/Global/SceneManager.gd +++ b/Scenes/Global/SceneManager.gd @@ -9,13 +9,16 @@ var loader = preload("res://Scenes/Loader.tscn") onready var netgame = $"/root/Multiplayer" func _ready() -> void: - queue.start(netgame.gotm_mode) + var threads_supported = true + if OS.get_name() == "HTML5": + threads_supported = false + queue.start(threads_supported) func enter_loader() -> void: get_tree().change_scene_to(loader) func load_scene(scene_path: String, dependencies: Array) -> void: - if not netgame.gotm_mode: + if queue.threaded: target_scene = scene_path queue.queue_resource(scene_path) for dep in dependencies: @@ -24,7 +27,7 @@ func load_scene(scene_path: String, dependencies: Array) -> void: get_tree().change_scene(scene_path) func _physics_process(_delta: float) -> void: - if not netgame.gotm_mode: + if queue.threaded: if target_scene != null: var remaining = queue.pending.size() for path in queue.pending: diff --git a/Scenes/Map.gd b/Scenes/Map.gd index ac3dded..4c11638 100644 --- a/Scenes/Map.gd +++ b/Scenes/Map.gd @@ -61,11 +61,8 @@ func _process(delta: float): if Engine.editor_hint: return - var current_speed_ratio = 0 var engines = get_engine_count() var max_speed = get_max_speed() - if engines > 0: - current_speed_ratio = current_ship_speed / max_speed # Ease ship speed/direction changes if abs(current_ship_direction) > PI*2: @@ -163,19 +160,14 @@ func serialize() -> Dictionary: data.append([cell, tilemap.get_cellv(cell)]) tilemapdata[tilemap.name] = data - # Get objects - var engines = serialize_children($engines) - var objects = serialize_children($objects) - var lights = serialize_children($lights) - var sockets = serialize_children($sockets) - var pois = serialize_children($pois) return { "tilemaps": tilemapdata, - "engines": engines, - "objects": objects, - "lights": lights, - "sockets": sockets, - "pois": pois, + "engines": serialize_children($engines), + "objects": serialize_children($objects), + "lights": serialize_children($lights), + "sockets": serialize_children($sockets), + "pois": serialize_children($pois), + "areas": serialize_children($areas), "ship": { "position": current_ship_position, "target": current_ship_target, @@ -201,6 +193,8 @@ func deserialize(data: Dictionary) -> void: deserialize_children($lights, data["lights"]) deserialize_children($pois, data["pois"]) deserialize_children($sockets, data["sockets"]) + deserialize_children($sockets, data["sockets"]) + deserialize_children($areas, data["areas"], true) # Set ship parameters current_ship_position = data["ship"]["position"] @@ -223,14 +217,17 @@ func serialize_children(node: Node) -> Dictionary: } return data -func deserialize_children(node: Node, data: Dictionary) -> void: +func deserialize_children(node: Node, data: Dictionary, deserialize_first: bool = false) -> void: for node_name in data: var node_data = data[node_name] as Dictionary var node_scene = load(node_data.filename).instance() node_scene.name = node_name node_scene.transform = node_data.transform + if deserialize_first: + node_scene.deserialize(node_data.data) node.add_child(node_scene, true) - node_scene.deserialize(node_data.data) + if not deserialize_first: + node_scene.deserialize(node_data.data) # Lighting diff --git a/Scenes/Maps/empty.tscn b/Scenes/Maps/empty.tscn index 373ef53..93b14a2 100644 --- a/Scenes/Maps/empty.tscn +++ b/Scenes/Maps/empty.tscn @@ -103,3 +103,5 @@ __meta__ = { [node name="pois" type="Node2D" parent="."] z_index = 999 + +[node name="areas" type="Node2D" parent="."] diff --git a/Scenes/Menu.gd b/Scenes/Menu.gd index 6df077d..46502f9 100644 --- a/Scenes/Menu.gd +++ b/Scenes/Menu.gd @@ -21,10 +21,6 @@ func _ready() -> void: $"/root/Music/BGM".play() netgame.connect("ms_updated", self, "_ms_update") request_servers() - if netgame.gotm_mode: - # Hide manual connect - $Popup/MarginContainer/VBoxContainer/Label2.visible = false - $Popup/MarginContainer/VBoxContainer/HBoxContainer.visible = false func _process(delta: float) -> void: refresh_server_remaining -= delta @@ -49,14 +45,9 @@ func _ms_update(action, result): if action == "list_games": # Reset server list server_list.clear() - if netgame.gotm_mode: - servers = result - for server in servers: - server_list.add_item(server.name + " (" + server.id + ") - " + str(server.peers.size()) + "/" + str(server.get_property("max_players")) + " players") - else: - servers = result - for server in servers: - server_list.add_item(server.data.name + " (" + server.address + ") - " + str(server.data.players) + "/" + str(server.data.max_players) + " players") + servers = result + for server in servers: + server_list.add_item(server.data.name + " (" + server.address + ") - " + str(server.data.players) + "/" + str(server.data.max_players) + " players") func set_scale(val) -> void: scale = val @@ -84,7 +75,7 @@ func _server_addr_changed(new_text: String) -> void: $Popup/MarginContainer/VBoxContainer/HBoxContainer/Button.disabled = new_text.length() < 1 func _manual_join_pressed(): - join_server($Popup/MarginContainer/VBoxContainer/HBoxContainer/LineEdit.text) + join_server({ "address": $Popup/MarginContainer/VBoxContainer/HBoxContainer/LineEdit.text }) func _server_item_clicked(index): $"/root/Music/BGM".stop() diff --git a/Scenes/UI.gd b/Scenes/UI.gd index 54d8737..bc6b965 100644 --- a/Scenes/UI.gd +++ b/Scenes/UI.gd @@ -2,8 +2,6 @@ extends Control class_name GameUI -signal command(command) - enum ServerMenuItem { ServerInfo } @@ -16,7 +14,7 @@ enum PopupName { onready var logs = $Logs onready var scene = $"/root/scene" -const CHAT_RADIUS = 32*6 +const CHAT_RADIUS = 32*10 func _ready() -> void: # Add options to menu buttons diff --git a/Scenes/UI.tscn b/Scenes/UI.tscn index 68fdf5b..06d38fb 100644 --- a/Scenes/UI.tscn +++ b/Scenes/UI.tscn @@ -1,11 +1,36 @@ -[gd_scene load_steps=6 format=2] +[gd_scene load_steps=15 format=2] [ext_resource path="res://Scenes/UI/SpaceMap.tscn" type="PackedScene" id=1] [ext_resource path="res://Scenes/UI.gd" type="Script" id=2] -[ext_resource path="res://Scenes/UI/Panels/Logs.tscn" type="PackedScene" id=3] +[ext_resource path="res://Graphics/UI/iosevka-aile-regular.ttf" type="DynamicFontData" id=3] [ext_resource path="res://Scenes/UI/Panels/ServerInfo.tscn" type="PackedScene" id=4] +[ext_resource path="res://Scenes/UI/Widgets/ResizablePanel.tscn" type="PackedScene" id=5] +[ext_resource path="res://Scenes/UI/Panels/Logs.gd" type="Script" id=6] +[ext_resource path="res://Graphics/UI/iosevka-aile-italic.ttf" type="DynamicFontData" id=7] +[ext_resource path="res://Graphics/UI/iosevka-aile-bold.ttf" type="DynamicFontData" id=8] +[ext_resource path="res://Graphics/UI/iosevka-aile-bolditalic.ttf" type="DynamicFontData" id=9] -[sub_resource type="StyleBoxFlat" id=1] +[sub_resource type="DynamicFont" id=1] +size = 14 +use_mipmaps = true +font_data = ExtResource( 9 ) + +[sub_resource type="DynamicFont" id=2] +size = 14 +use_mipmaps = true +font_data = ExtResource( 7 ) + +[sub_resource type="DynamicFont" id=3] +size = 14 +use_mipmaps = true +font_data = ExtResource( 8 ) + +[sub_resource type="DynamicFont" id=4] +size = 14 +use_mipmaps = true +font_data = ExtResource( 3 ) + +[sub_resource type="StyleBoxFlat" id=5] bg_color = Color( 0.133333, 0.12549, 0.203922, 0.705882 ) border_width_left = 4 border_width_top = 4 @@ -31,11 +56,53 @@ __meta__ = { [node name="MapPopup" parent="." instance=ExtResource( 1 )] -[node name="Logs" parent="." instance=ExtResource( 3 )] +[node name="Logs" type="Control" parent="."] margin_left = 10.0 margin_top = 10.0 -margin_right = -857.0 -margin_bottom = -566.0 +margin_right = 475.0 +margin_bottom = 273.0 +script = ExtResource( 6 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ResizablePanel" parent="Logs" instance=ExtResource( 5 )] +title = "Logs" + +[node name="RichTextLabel" type="RichTextLabel" parent="Logs/ResizablePanel"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 10.0 +margin_top = 40.0 +margin_right = -10.0 +margin_bottom = -40.0 +focus_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +custom_fonts/bold_italics_font = SubResource( 1 ) +custom_fonts/italics_font = SubResource( 2 ) +custom_fonts/bold_font = SubResource( 3 ) +custom_fonts/normal_font = SubResource( 4 ) +bbcode_enabled = true +selection_enabled = true +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="LineEdit" type="LineEdit" parent="Logs/ResizablePanel"] +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 6.0 +margin_top = -30.0 +margin_right = -16.0 +margin_bottom = -6.0 +focus_mode = 1 +caret_blink = true +caret_blink_speed = 0.5 +__meta__ = { +"_edit_use_anchors_": false +} [node name="Menu" type="PanelContainer" parent="."] anchor_left = 1.0 @@ -48,7 +115,7 @@ grow_horizontal = 0 grow_vertical = 0 size_flags_horizontal = 8 size_flags_vertical = 8 -custom_styles/panel = SubResource( 1 ) +custom_styles/panel = SubResource( 5 ) __meta__ = { "_edit_use_anchors_": false } @@ -90,3 +157,9 @@ margin_left = 31.2773 margin_top = 46.9222 margin_right = 287.277 margin_bottom = 214.923 +[connection signal="chat_message_sent" from="Logs" to="." method="_send_chat"] +[connection signal="focus_entered" from="Logs/ResizablePanel/LineEdit" to="Logs" method="_chat_bar_status" binds= [ true ]] +[connection signal="focus_exited" from="Logs/ResizablePanel/LineEdit" to="Logs" method="_chat_bar_status" binds= [ false ]] +[connection signal="mouse_entered" from="Logs/ResizablePanel/LineEdit" to="Logs" method="_chat_bar_focus" binds= [ true ]] +[connection signal="mouse_exited" from="Logs/ResizablePanel/LineEdit" to="Logs" method="_chat_bar_focus" binds= [ false ]] +[connection signal="text_entered" from="Logs/ResizablePanel/LineEdit" to="Logs" method="_text_submitted"] diff --git a/Scenes/UI/Panels/Logs.gd b/Scenes/UI/Panels/Logs.gd index 98e3549..9d59ba5 100644 --- a/Scenes/UI/Panels/Logs.gd +++ b/Scenes/UI/Panels/Logs.gd @@ -1,5 +1,7 @@ extends Control +signal chat_message_sent(text) + onready var log_text = $ResizablePanel/RichTextLabel onready var chat_bar = $ResizablePanel/LineEdit @@ -7,6 +9,8 @@ func _input(event: InputEvent) -> void: if event is InputEventMouseButton: if not chat_bar_focus: chat_bar.release_focus() + if event.is_action_released("ui_chat") and chat_bar_focus == false: + chat_bar.grab_focus() func add_line(line: String) -> void: log_text.append_bbcode(line) @@ -18,3 +22,8 @@ func _chat_bar_status(editing: bool) -> void: func _chat_bar_focus(entered: bool) -> void: chat_bar_focus = entered + +func _text_submitted(text): + emit_signal("chat_message_sent", text) + chat_bar.text = "" + chat_bar.release_focus() diff --git a/Scenes/UI/Panels/Logs.tscn b/Scenes/UI/Panels/Logs.tscn deleted file mode 100644 index 6c079b7..0000000 --- a/Scenes/UI/Panels/Logs.tscn +++ /dev/null @@ -1,76 +0,0 @@ -[gd_scene load_steps=11 format=2] - -[ext_resource path="res://Graphics/UI/iosevka-aile-regular.ttf" type="DynamicFontData" id=1] -[ext_resource path="res://Graphics/UI/iosevka-aile-italic.ttf" type="DynamicFontData" id=2] -[ext_resource path="res://Graphics/UI/iosevka-aile-bold.ttf" type="DynamicFontData" id=3] -[ext_resource path="res://Graphics/UI/iosevka-aile-bolditalic.ttf" type="DynamicFontData" id=4] -[ext_resource path="res://Scenes/UI/Panels/Logs.gd" type="Script" id=5] -[ext_resource path="res://Scenes/UI/Widgets/ResizablePanel.tscn" type="PackedScene" id=6] - -[sub_resource type="DynamicFont" id=1] -size = 14 -use_mipmaps = true -font_data = ExtResource( 4 ) - -[sub_resource type="DynamicFont" id=2] -size = 14 -use_mipmaps = true -font_data = ExtResource( 2 ) - -[sub_resource type="DynamicFont" id=3] -size = 14 -use_mipmaps = true -font_data = ExtResource( 3 ) - -[sub_resource type="DynamicFont" id=4] -size = 14 -use_mipmaps = true -font_data = ExtResource( 1 ) - -[node name="Logs" type="Control"] -anchor_right = 1.0 -anchor_bottom = 1.0 -script = ExtResource( 5 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="ResizablePanel" parent="." instance=ExtResource( 6 )] - -[node name="RichTextLabel" type="RichTextLabel" parent="ResizablePanel"] -anchor_right = 1.0 -anchor_bottom = 1.0 -margin_left = 10.0 -margin_top = 40.0 -margin_right = -10.0 -margin_bottom = -40.0 -focus_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -custom_fonts/bold_italics_font = SubResource( 1 ) -custom_fonts/italics_font = SubResource( 2 ) -custom_fonts/bold_font = SubResource( 3 ) -custom_fonts/normal_font = SubResource( 4 ) -bbcode_enabled = true -selection_enabled = true -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="LineEdit" type="LineEdit" parent="ResizablePanel"] -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -margin_left = 10.0 -margin_top = -30.0 -margin_right = -10.0 -focus_mode = 1 -caret_blink = true -caret_blink_speed = 0.5 -__meta__ = { -"_edit_use_anchors_": false -} -[connection signal="focus_entered" from="ResizablePanel/LineEdit" to="." method="_chat_bar_status" binds= [ true ]] -[connection signal="focus_exited" from="ResizablePanel/LineEdit" to="." method="_chat_bar_status" binds= [ false ]] -[connection signal="mouse_entered" from="ResizablePanel/LineEdit" to="." method="_chat_bar_focus" binds= [ true ]] -[connection signal="mouse_exited" from="ResizablePanel/LineEdit" to="." method="_chat_bar_focus" binds= [ false ]] diff --git a/Scenes/UI/Panels/ServerInfo.gd b/Scenes/UI/Panels/ServerInfo.gd index ec424ea..e2d9414 100644 --- a/Scenes/UI/Panels/ServerInfo.gd +++ b/Scenes/UI/Panels/ServerInfo.gd @@ -1,6 +1,5 @@ extends WindowDialog -func _physics_process(delta): +func _physics_process(_delta): if not visible: return - multiplayer diff --git a/Scenes/UI/SpaceMapInside.gd b/Scenes/UI/SpaceMapInside.gd index df80346..6b577f8 100644 --- a/Scenes/UI/SpaceMapInside.gd +++ b/Scenes/UI/SpaceMapInside.gd @@ -6,6 +6,7 @@ export var bgzoom = 50 const BORDER_WIDTH = 4 const BORDER_LENGTH = 30 const RADAR_EFFECT_DELAY = 1 +const HALF_BORDER = BORDER_LENGTH/2 export(Texture) var background export(Font) var font @@ -87,13 +88,13 @@ func draw_target(viewport: Rect2, position: Vector2, color: Color): var relative_pos = position - viewport.position var clamped = Vector2(clamp(relative_pos.x, 0, viewport.size.x), clamp(relative_pos.y, 0, viewport.size.y)) if relative_pos.x < 0: - draw_line(Vector2(0, clamped.y-BORDER_LENGTH/2), Vector2(0, clamped.y+BORDER_LENGTH/2), color, BORDER_WIDTH) + draw_line(Vector2(0, clamped.y-HALF_BORDER), Vector2(0, clamped.y+HALF_BORDER), color, BORDER_WIDTH) elif relative_pos.x > viewport.size.x: - draw_line(Vector2(viewport.size.x, clamped.y-BORDER_LENGTH/2), Vector2(viewport.size.x, clamped.y+BORDER_LENGTH/2), color, BORDER_WIDTH) + draw_line(Vector2(viewport.size.x, clamped.y-HALF_BORDER), Vector2(viewport.size.x, clamped.y+HALF_BORDER), color, BORDER_WIDTH) if relative_pos.y < 0: - draw_line(Vector2(clamped.x-BORDER_LENGTH/2, 0), Vector2(clamped.x+BORDER_LENGTH/2, 0), color, BORDER_WIDTH) + draw_line(Vector2(clamped.x-HALF_BORDER, 0), Vector2(clamped.x+HALF_BORDER, 0), color, BORDER_WIDTH) elif relative_pos.y > viewport.size.y: - draw_line(Vector2(clamped.x-BORDER_LENGTH/2, viewport.size.y), Vector2(clamped.x+BORDER_LENGTH/2, viewport.size.y), color, BORDER_WIDTH) + draw_line(Vector2(clamped.x-HALF_BORDER, viewport.size.y), Vector2(clamped.x+HALF_BORDER, viewport.size.y), color, BORDER_WIDTH) func _input(event): if event is InputEventMouseButton: diff --git a/export_presets.cfg b/export_presets.cfg index f25e504..def1c37 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -43,7 +43,7 @@ application/trademarks="" [preset.1] -name="GOTM" +name="HTML5" platform="HTML5" runnable=true custom_features="" diff --git a/gotm/Gotm.gd b/gotm/Gotm.gd deleted file mode 100644 index e68ab21..0000000 --- a/gotm/Gotm.gd +++ /dev/null @@ -1,117 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -extends Node -#warnings-disable - - -# Official GDScript API for games on gotm.io -# This plugin serves as a polyfill while developing against the API locally. - -# The 'real' API calls are only available when running the game live on gotm.io. -# Running the game in the web player (gotm.io/web-player) also counts as live. - -# Add this script as a global autoload. Make sure the global autoload is named -# "Gotm". It must be named "Gotm" for it to work. - - -############################################################## -# SIGNALS -############################################################## -# You connected or disconnected from a lobby. Access it at 'Gotm.lobby' -signal lobby_changed() - -# Files were drag'n'dropped into the screen. -# The 'files' argument is an array of 'GotmFile'. -signal files_dropped(files, screen) - - - -############################################################## -# PROPERTIES -############################################################## -# These are all read only. - -# Player information. -var user: GotmUser = GotmUser.new() - -# Current lobby you are in. -# Is null when not in a lobby. -var lobby: GotmLobby = null - - -############################################################## -# METHODS -############################################################## - -# The API is live when the game runs on gotm.io. -# Running the game in the web player (gotm.io/web-player) also counts as live. -func is_live() -> bool: - return false - - -# Create a new lobby and join it. -# -# If 'show_invitation' is true, show an invitation link in a popup. -# -# By default, the lobby is hidden and is only accessible directly through -# its 'invite_link'. -# Set 'lobby.hidden' to false to make it fetchable with 'GotmLobbyFetch'. -# -# Returns the hosted lobby (also accessible at 'Gotm.lobby'). -static func host_lobby(show_invitation: bool = true) -> GotmLobby: - return _GotmImpl._host_lobby(GotmLobby.new()) - - -# Play an audio snippet with 'message' as a synthesized voice. -# 'language' is in BCP 47 format (e.g. "en-US" for american english). -# If specified language is not available "en-US" is used. -# Return true if playback succeeded. -func text_to_speech(message: String, language: String = "en-US") -> bool: - return true # pretend it worked - - -# Asynchronously open up the browser's file picker. -# -# If 'types' is specified, limit the file picker to files with matching file -# types (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers). -# If 'only_one' is true, only allow the user to pick one file. -# -# If a picking-session is already in progress, an empty -# array is asynchronously returned. -# -# Asynchronously return an array of 'GotmFile'. -# Use 'yield(pick_files(), "completed")' to retrieve the return value. -func pick_files(types: Array = Array(), only_one: bool = false) -> Array: - yield(get_tree().create_timer(0.25), "timeout") - return [] - - - -############################################################## -# PRIVATE -############################################################## -func _ready() -> void: - _GotmImpl._initialize(GotmLobby, GotmUser) -func _process(delta) -> void: - _GotmImpl._process() -var _impl: Dictionary = {} diff --git a/gotm/GotmDebug.gd b/gotm/GotmDebug.gd deleted file mode 100644 index 1c14f1f..0000000 --- a/gotm/GotmDebug.gd +++ /dev/null @@ -1,65 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -class_name GotmDebug -#warnings-disable - -# Helper library for testing against the API locally, as if it would be live. -# -# These functions do not make real API calls. They fake operations and -# trigger relevant signals as if they happened live. -# -# These functions do nothing when the game is running live on gotm.io. -# Running the game in the web player (gotm.io/web-player) also counts as live. - -# Host a lobby without joining it. -# Note that the lobby is hidden by default and not fetchable with -# 'GotmLobbyFetch'. To make it fetchable, set 'hidden' to false. -# The lobby is only fetchable and joinable in this game process. -# Returns added lobby. -static func add_lobby() -> GotmLobby: - return _GotmDebugImpl._add_lobby(GotmLobby.new()) - - -# Remove a lobby created with 'add_lobby', as if its host (you) disconnected from it. -# Triggers 'lobby_changed' if you are in that lobby. -static func remove_lobby(lobby: GotmLobby) -> void: - _GotmDebugImpl._remove_lobby(lobby) - - -# Remove all lobbies. -static func clear_lobbies() -> void: - _GotmDebugImpl._clear_lobbies() - - -# Add yourself to the lobby, without joining it. -# Triggers 'peer_joined' if you are in that lobby. -# Returns joined peer. -static func add_lobby_peer(lobby: GotmLobby) -> GotmUser: - return _GotmDebugImpl._add_lobby_player(lobby, GotmUser.new()) - - -# Remove a peer created with 'add_lobby_peer' from the lobby, as if the peer (you) disconnected -# from the lobby. -# Triggers 'peer_left' if you are in that lobby. -static func remove_lobby_peer(lobby: GotmLobby, peer: GotmUser) -> void: - _GotmDebugImpl._remove_lobby_player(lobby, peer) diff --git a/gotm/GotmFile.gd b/gotm/GotmFile.gd deleted file mode 100644 index c5938e6..0000000 --- a/gotm/GotmFile.gd +++ /dev/null @@ -1,50 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -class_name GotmFile -#warnings-disable - -# A simple in-memory file descriptor used by 'Gotm.pick_files' and -# 'Gotm.files_dropped'. - - - -############################################################## -# PROPERTIES -############################################################## -# File name. -var name: String - -# File data. -var data: PoolByteArray - -# Last time the file was modified in unix time (seconds since epoch). -var modified_time: int - - - -############################################################## -# METHODS -############################################################## -# Save the file to the browser's download folder. -func download() -> void: - pass diff --git a/gotm/GotmLobby.gd b/gotm/GotmLobby.gd deleted file mode 100644 index 90656e6..0000000 --- a/gotm/GotmLobby.gd +++ /dev/null @@ -1,155 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -class_name GotmLobby -#warnings-disable - -# A lobby is a way of connecting players with eachother as if they -# were on the same local network. -# -# Lobbies can be joined either directly through an 'invite_link', or by -# joining lobbies fetched with the 'GotmLobbyFetch' class. - -############################################################## -# SIGNALS -############################################################## -# Peer joined the lobby. -# 'peer_user' is a 'GotmUser' instance. -# This is only emitted if you are in this lobby. -signal peer_joined(peer_user) - -# Peer left the lobby. -# 'peer_user' is a 'GotmUser' instance. -# This is only emitted if you are in this lobby. -signal peer_left(peer_user) - - - -############################################################## -# READ-ONLY PROPERTIES -############################################################## -# Globally unique identifier. -var id: String - -# Other peers in the lobby with addresses. -# Is an array of 'GotmUser'. -var peers: Array = [] - -# You with address. -var me: GotmUser = GotmUser.new() - -# Host user with address. -var host: GotmUser = GotmUser.new() - -# Peers can join the lobby directly through this link. -var invite_link: String - - - -############################################################## -# WRITABLE PROPERTIES -############################################################## -# Note that only the host can write to these properties. - -# Name that is searchable using 'GotmLobbyFetch' -# Names longer than 64 characters are truncated. -var name: String = "" - -# Prevent the lobby from showing up in fetches? -# Peers may still join directly through 'invite_link' -var hidden: bool = true - -# Prevent new peers from joining? -# Also prevents the lobby from showing up in fetches. -var locked: bool = false - - - -############################################################## -# METHODS -############################################################## -# Asynchronously join this lobby after leaving current lobby. -# -# Use 'var success = yield(lobby.join(), "completed")' to wait for the call to complete -# and retrieve the return value. -# -# Sets 'Gotm.lobby' to the joined lobby if successful. -# -# Asyncronously returns true if successful, else false. -func join() -> bool: - return yield(_GotmImpl._join_lobby(self), "completed") - - -# Leave this lobby. -func leave() -> void: - _GotmImpl._leave_lobby(self) - - -# Am I the host of this lobby? -func is_host() -> bool: - return _GotmImpl._is_lobby_host(self) - - -# Get a custom property. -func get_property(name: String): - return _GotmImpl._get_lobby_property(self, name) - - - -################################ -# Host-only methods -################################ -# Kick peer from this lobby. -# Returns true if successful, else false. -func kick(peer: GotmUser) -> bool: - return _GotmImpl._kick_lobby_peer(self, peer) - - -# Store up to 10 of your own custom properties in the lobby. -# These are visible to other peers when fetching lobbies. -# Only properties of types String, int, float or bool are allowed. -# Integers are converted to floats. -# Strings longer than 64 characters are truncated. -# Setting 'value' to null removes the property. -func set_property(name: String, value) -> void: - _GotmImpl._set_lobby_property(self, name, value) - - -# Make this lobby filterable by a custom property. -# Filtering is done when fetching lobbies with 'GotmLobbyFetch'. -# Up to 3 properties can be set as filterable at once. -func set_filterable(property_name: String, filterable: bool = true) -> void: - _GotmImpl._set_lobby_filterable(self, property_name, filterable) - - -# Make this lobby sortable by a custom property. -# Sorting is done when fetching lobbies with 'GotmLobbyFetch'. -# Up to 3 properties can be set as sortable at once. -func set_sortable(property_name: String, sortable: bool = true) -> void: - _GotmImpl._set_lobby_sortable(self, property_name, sortable) - - - -################################ -# PRIVATE -################################ -var _impl: Dictionary = {} diff --git a/gotm/GotmLobbyFetch.gd b/gotm/GotmLobbyFetch.gd deleted file mode 100644 index 9f3748f..0000000 --- a/gotm/GotmLobbyFetch.gd +++ /dev/null @@ -1,122 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -class_name GotmLobbyFetch -#warnings-disable - -# Used for fetching non-hidden and non-locked lobbies. - - - -############################################################## -# PROPERTIES -############################################################## -################ -# Filter options -################ -# If not empty, fetch lobbies whose 'Lobby.name' contains 'name'. -var filter_name: String = "" - -# If not empty, fetch lobbies whose filterable custom properties -# matches those in 'filter_properties'. -# -# For example, setting 'filter_properties.difficulty = 2' will -# only fetch lobbies that have been set up with both 'lobby.set_property("difficulty", 2)' -# and 'lobby.set_filterable("difficulty", true)'. -# -# If your lobby has multiple filterable props, you must provide every filterable -# prop in 'filter_properties'. Setting a prop's value to 'null' will match any -# value of that prop. -var filter_properties: Dictionary = {} - - -################ -# Sort options -################ -# If not empty, sort by a sortable custom property. -# -# For example, setting 'sort_property = "difficulty"' will -# only fetch lobbies that have been set up with both 'lobby.set_property("difficulty", some_value)' -# and 'lobby.set_sortable("difficulty", true)'. -# -# If your lobby has a sortable prop, you must always provide a 'sort_property'. -var sort_property: String = "" - -# Sort results in ascending order? -var sort_ascending: bool = false - -# If not null, fetch lobbies whose sort property's value is equal to or greater than 'sort_min'. -var sort_min = null - -# If not null, fetch lobbies whose sort property's value is equal to or lesser than 'sort_max'. -var sort_max = null - -# If true, and 'sort_min' is provided, exclude lobbies whose sort property's value is equal to 'sort_min'. -var sort_min_exclusive = false - -# If true, and 'sort_max' is provided, exclude lobbies whose sort property's value is equal to 'sort_max'. -var sort_max_exclusive = false - - - -############################################################## -# METHODS -############################################################## -# All these methods asynchronously fetch up to 8 non-hidden -# and non-locked lobbies. -# -# Modifying any filtering or sorting option resets the state of this -# 'GotmLobbyFetch' instance and causes the next fetch call to -# fetch the first lobbies. -# -# All calls asynchronously return an array of fetched lobbies. -# Use 'yield(fetch.next(), "completed")' to retrieve it. - - -# Fetch the next lobbies, starting after the last lobby fetched -# in the previous call. -func next(count: int = 8) -> Array: - return yield(_GotmImpl._fetch_lobbies(self, count, "next"), "completed") - - -# Fetch the previous lobbies, ending before the first lobby -# that was fetched in the previous call. -func previous(count: int = 8) -> Array: - return yield(_GotmImpl._fetch_lobbies(self, count, "previous"), "completed") - - -# Fetch the first lobbies. -func first(count: int = 8) -> Array: - return yield(_GotmImpl._fetch_lobbies(self, count, "first"), "completed") - - -# Fetch lobbies at the current position. -# Useful for refreshing lobbies without changing the page. -func current(count: int = 8) -> Array: - return yield(_GotmImpl._fetch_lobbies(self, count, "current"), "completed") - - - -############################################################## -# PRIVATE -############################################################## -var _impl: Dictionary = {} diff --git a/gotm/GotmUser.gd b/gotm/GotmUser.gd deleted file mode 100644 index e4a5021..0000000 --- a/gotm/GotmUser.gd +++ /dev/null @@ -1,52 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -class_name GotmUser -#warnings-disable - -# Holds information about a Gotm user. - - - -############################################################## -# PROPERTIES -############################################################## -# These are all read-only. - -# Globally unique ID. -# Is empty if user is not logged in. -var id: String = "" - -# Current nickname. -var display_name: String = "" - -# The IP address of the user. -# Is empty if you are not in the same lobby. -var address: String = "" - -# Is user logged in? -var is_logged_in: bool = false - -############################################################## -# PRIVATE -############################################################## -var _impl: Dictionary = {} diff --git a/gotm/LICENSE b/gotm/LICENSE deleted file mode 100644 index 8195d8a..0000000 --- a/gotm/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020-2020 Macaroni Studios AB - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/gotm/README.md b/gotm/README.md deleted file mode 100644 index caf63d6..0000000 --- a/gotm/README.md +++ /dev/null @@ -1,30 +0,0 @@ -

- gotm.io -
- Access Gotm's API with GDScript -
- Learn more -

- -# Install - -_Supports versions 3.1.0 and newer._ - -## 1. Download - -Download the plugin from the [AssetLib](https://docs.godotengine.org/en/stable/tutorials/assetlib/using_assetlib.html#in-the-editor) in the Godot Editor and follow its instructions. - -You can also download it directly [here](https://github.com/PlayGotm/GDGotm/archive/master.zip). Extract the contents into your project's directory. - -## 2. Setup - -Add Gotm.gd to your autoloads at "Project Settings -> AutoLoad". Make sure the global autoload is named "Gotm". It must be named "Gotm" for it to work. - -# Examples - -[Examples](https://github.com/PlayGotM/game-examples) - -# Notes - -This plugin serves as a polyfill when developing against the API locally. -The "real" API calls are only available when running the game live on gotm.io. diff --git a/gotm/_impl/_GotmDebugImpl.gd b/gotm/_impl/_GotmDebugImpl.gd deleted file mode 100644 index 482a8a5..0000000 --- a/gotm/_impl/_GotmDebugImpl.gd +++ /dev/null @@ -1,108 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -class_name _GotmDebugImpl -#warnings-disable - -static func _login() -> void: - var g = _GotmImpl._get_gotm() - if g.is_live(): - return - - _logout() - - g.user_id = _GotmImpl._generate_id() - g.emit_signal("user_changed") - - -static func _logout() -> void: - var g = _GotmImpl._get_gotm() - if g.is_live(): - return - - if !g.has_user(): - return - - g.user_id = "" - g.emit_signal("user_changed") - - -static func _add_lobby(lobby): - var g = _GotmImpl._get_gotm() - if g.is_live(): - return lobby - - lobby = _GotmImpl._add_lobby(lobby) - lobby._impl.address = "127.0.0.1" - lobby._impl.host_id = g.user._impl.id - lobby.host._impl.id = g.user._impl.id - lobby.peers = [] - return lobby - - -static func _remove_lobby(lobby) -> void: - var g = _GotmImpl._get_gotm() - if g.is_live(): - return - - _GotmImpl._leave_lobby(lobby) - g._impl.lobbies.erase(lobby) - - -static func _clear_lobbies() -> void: - var g = _GotmImpl._get_gotm() - if g.is_live(): - return - - for lobby in g._impl.lobbies.duplicate(): - _remove_lobby(lobby) - - -static func _add_lobby_player(lobby, peer): - var g = _GotmImpl._get_gotm() - if g.is_live(): - return null - - peer.address = "127.0.0.1" - peer._impl.id = peer._impl.id - lobby.peers.push_back(peer) - if lobby == g.lobby: - lobby.emit_signal("peer_joined", peer) - return peer - - -static func _remove_lobby_player(lobby, peer) -> void: - var g = _GotmImpl._get_gotm() - if g.is_live(): - return - - for p in lobby.peers.duplicate(): - if peer._impl.id != p._impl.id: - continue - if peer._impl.id == lobby.host._impl.id: - _remove_lobby(lobby) - else: - lobby.peers.erase(p) - if lobby == g.lobby: - lobby.emit_signal("peer_left", p) - - diff --git a/gotm/_impl/_GotmImpl.gd b/gotm/_impl/_GotmImpl.gd deleted file mode 100644 index 236ce13..0000000 --- a/gotm/_impl/_GotmImpl.gd +++ /dev/null @@ -1,586 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -class_name _GotmImpl -#warnings-disable - - -# Utility sorter for 'sort_custom'. -class LobbySorter: - var fetch - var g - - func sort(lhs, rhs) -> bool: - var a - var b - if fetch.sort_property.empty(): - a = lhs._impl.created - b = rhs._impl.created - else: - a = lhs._impl.props[fetch.sort_property] - b = rhs._impl.props[fetch.sort_property] - - if fetch.sort_ascending: - return _GotmImplUtility.is_less(a, b) - else: - return _GotmImplUtility.is_greater(a, b) - - -# Generate 20 characters long random string. -static func _generate_id() -> String: - var g = _get_gotm() - var id: String = "" - for i in range(20): - id += g._impl.chars[g._impl.rng.randi() % g._impl.chars.length()] - return id - - -# Retrieve scene statically via Engine singleton. -static func _get_tree() -> SceneTree: - return Engine.get_main_loop() as SceneTree - - -# Get autoloaded Gotm instance from scene's root. -static func _get_gotm() -> Node: - return _get_tree().root.get_node("Gotm") - - -# Simplify string somewhat. We want exact matches, but with some reasonable fuzziness. -static func _init_search_string_encoders() -> Array: - var encoders: Array = [ - ["[àáâãäå]", "a"], - ["[èéêë]", "e"], - ["[ìíîï]", "i"], - ["[òóôõöő]", "o"], - ["[ùúûüű]", "u"], - ["[ýŷÿ]", "y"], - ["ñ", "n"], - ["[çc]", "k"], - ["ß", "s"], - ["[-/]", " "], - ["[^a-z0-9 ]", ""], - ["\\s+", " "], - ["^\\s+", ""], - ["\\s+$", ""] - ] - for encoder in encoders: - var regex: RegEx = RegEx.new() - regex.compile(encoder[0]) - encoder[0] = regex - - return encoders - - -# Initialize socket for fetching lobbies on local network. -static func _init_socket() -> void: - var g = _get_gotm() - if not g._impl.sockets: - g._impl.sockets = [] - var is_listening = false - for i in range(5): - var socket = PacketPeerUDP.new() - if socket.has_method("set_broadcast_enabled"): - socket.set_broadcast_enabled(true) - if not is_listening: - is_listening = socket.listen(8075 + i) == OK - socket.set_dest_address("255.255.255.255", 8075 + i) - g._impl.sockets.push_back(socket) - - if not is_listening: - push_error("Failed to listen for lobbies. All ports 8075-8079 are busy.") - - -# Attach some global state to autoloaded Gotm instance. -static func _initialize(GotmLobbyT, GotmUserT) -> void: - var g = _get_gotm() - - g._impl = { - "lobbies": [], - "chars": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-", - "rng": RandomNumberGenerator.new(), - "search_string_encoders": _init_search_string_encoders(), - "sockets": null, - "lobby_requests": {}, - "GotmLobbyT": GotmLobbyT, - "GotmUserT": GotmUserT, - "is_listening": false - } - g._impl.rng.randomize() - g.user._impl.id = _generate_id() - g.user.address = "localhost" - - -static func _process() -> void: - var g = _get_gotm() - - if g.lobby: - if OS.get_system_time_msecs() - g.lobby._impl.last_heartbeat > 2500: - _init_socket() - _put_sockets({ - "op": "peer_heartbeat", - "data": { - "lobby_id": g.lobby.id, - "id": g.user._impl.id - } - }) - g.lobby._impl.last_heartbeat = OS.get_system_time_msecs() - - if g._impl.sockets: - for socket in g._impl.sockets: - while socket.get_available_packet_count() > 0: - var v = socket.get_var() - if v.op == "get_lobbies": - var data = null - if g.lobby and g.lobby.is_host(): - data = { - "id": g.lobby.id, - "name": g.lobby.name, - "peers": [], - "invite_link": g.lobby.invite_link, - "_impl": g.lobby._impl - } - - _put_sockets({"op": "lobby", "data": data, "id": v.id}) - elif v.op == "leave_lobby": - if g.lobby and v.data.lobby_id == g.lobby.id: - if g.lobby.is_host(): - _put_sockets({ - "op": "peer_left", - "data": { - "lobby_id": g.lobby.id, - "id": v.data.id - } - }) - elif v.data.id == g.lobby.host._impl.id: - _leave_lobby(g.lobby) - elif v.op == "join_lobby": - var data = null - if g.lobby and g.lobby.is_host() and v.data.lobby_id == g.lobby.id: - _put_sockets({ - "op": "peer_joined", - "data": { - "lobby_id": g.lobby.id, - "address": socket.get_packet_ip(), - "id": v.data.id - }, - "id": v.id - }) - - var peers = [] - for peer in g.lobby.peers: - peers.push_back({"address": peer.address, "_impl": peer._impl}) - data = { - "id": g.lobby.id, - "name": g.lobby.name, - "peers": peers, - "invite_link": g.lobby.invite_link, - "_impl": g.lobby._impl - } - _put_sockets({"op": "lobby", "data": data, "id": v.id}) - elif v.op == "peer_left": - if g.lobby and v.data.lobby_id == g.lobby.id: - for peer in g.lobby.peers.duplicate(): - if peer._impl.id == v.data.id: - g.lobby.peers.erase(peer) - g.lobby.emit_signal("peer_left", peer) - elif v.op == "peer_joined": - if g.lobby and v.data.lobby_id == g.lobby.id and not g._impl.lobby_requests.has(v.id): - var peer = g._impl.GotmUserT.new() - peer.address = v.data.address - peer._impl.id = v.data.id - g.lobby.peers.push_back(peer) - g.lobby.emit_signal("peer_joined", peer) - if g.lobby.is_host(): - g.lobby._impl.heartbeats[v.data.id] = OS.get_system_time_msecs() - elif v.op == "peer_heartbeat": - if g.lobby and v.data.lobby_id == g.lobby.id: - g.lobby._impl.heartbeats[v.data.id] = OS.get_system_time_msecs() - elif v.op == "lobby": - if v.data and g._impl.lobby_requests.has(v.id): - var lobby = g._impl.GotmLobbyT.new() - var peers = [] - if not v.data._impl.host_id.empty(): - v.data.peers.push_back({ - "address": socket.get_packet_ip(), - "_impl": { - "id": v.data._impl.host_id - } - }) - for peer in v.data.peers: - var p = g._impl.GotmUserT.new() - p.address = peer.address - p._impl = peer._impl - peers.push_back(p) - - lobby.hidden = false - lobby.locked = false - lobby.id = v.data.id - lobby.name = v.data.name - lobby.peers = peers - lobby.invite_link = v.data.invite_link - lobby._impl = v.data._impl - lobby._impl.address = socket.get_packet_ip() - lobby.me.address = "127.0.0.1" - lobby.host.address = socket.get_packet_ip() - lobby.host._impl.id = v.data._impl.host_id - g._impl.lobby_requests[v.id].push_back(lobby) - - if g.lobby: - for peer_id in g.lobby._impl.heartbeats.duplicate(): - if OS.get_system_time_msecs() - g.lobby._impl.heartbeats[peer_id] > 10000: - if g.lobby.is_host(): - _put_sockets({ - "op": "peer_left", - "data": { - "lobby_id": g.lobby.id, - "id": peer_id - } - }) - g.lobby._impl.heartbeats.erase(peer_id) - elif peer_id == g.lobby.host._impl.id: - _leave_lobby(g.lobby) - break - - - - -# Improve search experience a little by adding fuzziness. -static func _encode_search_string(s: String) -> String: - s = s.to_lower() - var encoders: Array = _get_gotm()._impl.search_string_encoders - for encoder in encoders: - s = encoder[0].sub(s, encoder[1], true) - return s - - -# Return true if 'lobby' matches filter options in 'fetch'. -static func _match_lobby(lobby, fetch) -> bool: - if lobby.locked or lobby.hidden: - return false - - if not fetch.filter_name.empty(): - var name: String = _encode_search_string(lobby.name) - var query: String = _encode_search_string(fetch.filter_name) - if not query.empty() and name.find(query) < 0: - return false - - var lobby_props: Dictionary = {} - for key in lobby._impl.filterable_props: - if not lobby._impl.props.has(key): - return false - if not fetch.filter_properties.has(key): - return false - - var lhs = fetch.filter_properties[key] - var rhs = lobby._impl.props[key] - if lhs != null and lhs != rhs: - return false - - return true - - -# Used to detect changes. -static func _stringify_fetch_state(fetch) -> String: - var d: Array = [ - fetch.filter_name, - fetch.filter_properties, - fetch.sort_property, - fetch.sort_property, - fetch.sort_ascending, - fetch.sort_min, - fetch.sort_max, - fetch.sort_min_exclusive, - fetch.sort_max_exclusive - ] - return JSON.print(d) - - - -# Return sorted copy of 'lobbies' using sort options in 'fetch'. -static func _sort_lobbies(lobbies: Array, fetch) -> Array: - var sorted: Array = [] - var g = _get_gotm() - for lobby in lobbies: - if fetch.sort_property.empty(): - sorted.push_back(lobby) - - var v = lobby._impl.props.get(fetch.sort_property) - if v == null: - continue - if fetch.sort_min != null: - if _GotmImplUtility.is_less(v, fetch.sort_min): - continue - if fetch.sort_min_exclusive and not _GotmImplUtility.is_greater(v, fetch.sort_min): - continue - if fetch.sort_max != null: - if _GotmImplUtility.is_greater(v, fetch.sort_max): - continue - if fetch.sort_max_exclusive and not _GotmImplUtility.is_less(v, fetch.sort_max): - continue - - sorted.push_back(lobby) - - - var sorter: LobbySorter = LobbySorter.new() - sorter.fetch = fetch - sorter.g = g - sorted.sort_custom(sorter, "sort") - - return sorted - - -static func _put_sockets(v: Dictionary): - _init_socket() - for socket in _get_gotm()._impl.sockets: - socket.put_var(v) - - -static func _request_lobbies() -> Array: - var g = _get_gotm() - var request_id: String = _generate_id() - g._impl.lobby_requests[request_id] = [] - _put_sockets({"op": "get_lobbies", "id": request_id}) - yield(g.get_tree().create_timer(0.5), "timeout") - - var lobbies = g._impl.lobby_requests[request_id] - g._impl.lobby_requests.erase(request_id) - return lobbies - - -static func _request_join(lobby_id: String): - var g = _get_gotm() - var request_id: String = _generate_id() - g._impl.lobby_requests[request_id] = [] - _put_sockets({ - "op": "join_lobby", - "id": request_id, - "data": { - "lobby_id": lobby_id, - "id": g.user._impl.id - } - }) - yield(g.get_tree().create_timer(0.5), "timeout") - - var lobbies = g._impl.lobby_requests[request_id] - g._impl.lobby_requests.erase(request_id) - for lobby in lobbies: - if lobby: - return lobby - return null - - -static func _fetch_lobbies(fetch, count: int, type: String) -> Array: - var g = _get_gotm() - - # Reset fetch state if user has modified any options. - var stringified_state: String = _stringify_fetch_state(fetch) - if not fetch._impl.has("last_state") or stringified_state != fetch._impl.last_state: - fetch._impl.last_state = stringified_state - fetch._impl.last_lobby = -1 - fetch._impl.start_lobby = -1 - - - # Apply filter options - var lobbies: Array = [] - for lobby in yield(_request_lobbies(), "completed") + g._impl.lobbies: - if _match_lobby(lobby, fetch): - lobbies.push_back(lobby) - - # Apply sort options - lobbies = _sort_lobbies(lobbies, fetch) - count = min(8, count) - var index: int = 0 - if type == "first": - index = 0 - elif type == "next": - index = fetch._impl.last_lobby + 1 - elif type == "current": - index = fetch._impl.start_lobby + 1 - elif type == "previous": - index = max(fetch._impl.start_lobby - count, 0) - - # Get 'count' lobbies. - var result: Array = [] - for i in range(index, min(index + count, lobbies.size())): - result.push_back(lobbies[i]) - - # Write down last lobby for subsequent 'next' calls. - if not result.empty(): - var start: int = lobbies.find(result.front()) - 1 - fetch._impl.start_lobby = max(start, -1) - fetch._impl.last_lobby = lobbies.find(result.back()) - elif index > 0: - fetch._impl.start_lobby = fetch._impl.last_lobby - - yield(_get_tree().create_timer(0.25), "timeout") # fake delay - return result - - -# Common initialization. -static func _add_lobby(lobby): - var g = _get_gotm() - - lobby.id = _generate_id() - lobby.invite_link = "https://gotm.io/my-studio/my-game/" - lobby.invite_link += "?connectToken=" + _generate_id() - lobby._impl = { - # Not exposed to user, so doesn't have to be a real timestamp. - "created": OS.get_system_time_msecs(), - "props": {}, - "sortable_props": [], - "filterable_props": [], - "heartbeats": {}, - "last_heartbeat": 0, - "host_id": "", - "address": "" - } - lobby.me._impl.id = g.user._impl.id - - g._impl.lobbies.push_back(lobby) - return lobby - - -static func _host_lobby(lobby): - var g = _get_gotm() - _leave_lobby(g.lobby) - - lobby = _add_lobby(lobby) - lobby._impl.address = "127.0.0.1" - lobby.host.address = "127.0.0.1" - lobby._impl.host_id = g.user._impl.id - lobby.host._impl.id = g.user._impl.id - lobby.me.address = "127.0.0.1" - g.lobby = lobby - g.emit_signal("lobby_changed") - - _init_socket() - - return lobby - - -static func _join_lobby(lobby) -> bool: - var g = _get_gotm() - _leave_lobby(g.lobby) - - if not g._impl.lobbies.has(lobby): - lobby = yield(_request_join(lobby.id), "completed") - else: - yield(g.get_tree().create_timer(0.25), "timeout") - - if not lobby or lobby.locked: - return false - - lobby.host.address = lobby._impl.address - lobby.host._impl.id = lobby._impl.host_id - lobby.me.address = "127.0.0.1" - g.lobby = lobby - g.emit_signal("lobby_changed") - return true - - -static func _is_lobby_host(lobby) -> bool: - var g = _get_gotm() - return lobby.host._impl.id == g.user._impl.id - - -static func _kick_lobby_peer(lobby, peer) -> bool: - var g = _get_gotm() - - if not lobby.is_host(): - return false - - if g.user._impl.id == peer._impl.id: - _leave_lobby(lobby) - else: - for p in lobby.peers.duplicate(): - if p._impl.id != peer._impl.id: - continue - lobby.peers.erase(p) - if lobby == g.lobby: - lobby.emit_signal("peer_left", p) - break - - return true - - -static func _leave_lobby(lobby) -> void: - if not lobby: - return - - var g = _get_gotm() - if g.lobby == lobby: - if lobby.host.address == lobby.me.address: - g._impl.lobbies.erase(lobby) - lobby.me.address = "" - lobby.host.address = "" - _put_sockets({ - "op": "leave_lobby", - "data": { - "lobby_id": lobby.id, - "id": g.user._impl.id - } - }) - g.lobby = null - g.emit_signal("lobby_changed") - - -static func _truncate_string(s: String) -> String: - return s.substr(0, 64) - -static func _set_lobby_property(lobby, name: String, value) -> void: - name = _truncate_string(name) - if value == null: - lobby._impl.props.erase(name) - - match typeof(value): - TYPE_BOOL: - pass - TYPE_INT: - pass - TYPE_REAL: - pass - TYPE_STRING: - value = _truncate_string(value) - _: - push_error("Invalid lobby property type.") - return - - lobby._impl.props[name] = value - - -static func _get_lobby_property(lobby, name: String): - return lobby._impl.props[_truncate_string(name)] - -static func _set_lobby_filterable(lobby, property_name: String, filterable: bool) -> void: - property_name = _truncate_string(property_name) - if not filterable: - lobby._impl.filterable_props.erase(property_name) - elif not lobby._impl.filterable_props.has(property_name): - lobby._impl.filterable_props.push_back(property_name) - - -static func _set_lobby_sortable(lobby, property_name: String, sortable: bool) -> void: - property_name = _truncate_string(property_name) - if not sortable: - lobby._impl.sortable_props.erase(property_name) - elif not lobby._impl.sortable_props.has(property_name): - lobby._impl.sortable_props.push_back(property_name) diff --git a/gotm/_impl/_GotmImplUtility.gd b/gotm/_impl/_GotmImplUtility.gd deleted file mode 100644 index 7528ab7..0000000 --- a/gotm/_impl/_GotmImplUtility.gd +++ /dev/null @@ -1,48 +0,0 @@ -# MIT License -# -# Copyright (c) 2020-2020 Macaroni Studios AB -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -class_name _GotmImplUtility -#warnings-disable - - -static func _fuzzy_compare(a, b, compare_less: bool) -> bool: - if typeof(a) == typeof(b): - return a < b if compare_less else a > b - - # GDScript doesn't handle comparison of different types very well. - # Abuse Array's min and max functions instead. - var m = [a, b].min() if compare_less else [a, b].max() - if m != null or a == null or b == null: - return m == a - - # Array method failed. Go with strings instead. - a = String(a) - b = String(b) - return a < b if compare_less else a > b - - -static func is_less(a, b) -> bool: - return _fuzzy_compare(a, b, true) - - -static func is_greater(a, b) -> bool: - return _fuzzy_compare(a, b, false) \ No newline at end of file diff --git a/project.godot b/project.godot index a8f5b0b..4279e4b 100644 --- a/project.godot +++ b/project.godot @@ -74,31 +74,6 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://Scenes/World.gd" }, { -"base": "Reference", -"class": "GotmDebug", -"language": "GDScript", -"path": "res://gotm/GotmDebug.gd" -}, { -"base": "Reference", -"class": "GotmFile", -"language": "GDScript", -"path": "res://gotm/GotmFile.gd" -}, { -"base": "Reference", -"class": "GotmLobby", -"language": "GDScript", -"path": "res://gotm/GotmLobby.gd" -}, { -"base": "Reference", -"class": "GotmLobbyFetch", -"language": "GDScript", -"path": "res://gotm/GotmLobbyFetch.gd" -}, { -"base": "Reference", -"class": "GotmUser", -"language": "GDScript", -"path": "res://gotm/GotmUser.gd" -}, { "base": "TileMap", "class": "MapTiles", "language": "GDScript", @@ -143,21 +118,6 @@ _global_script_classes=[ { "class": "UICommand", "language": "GDScript", "path": "res://Classes/UICommand.gd" -}, { -"base": "Reference", -"class": "_GotmDebugImpl", -"language": "GDScript", -"path": "res://gotm/_impl/_GotmDebugImpl.gd" -}, { -"base": "Reference", -"class": "_GotmImpl", -"language": "GDScript", -"path": "res://gotm/_impl/_GotmImpl.gd" -}, { -"base": "Reference", -"class": "_GotmImplUtility", -"language": "GDScript", -"path": "res://gotm/_impl/_GotmImplUtility.gd" } ] _global_script_class_icons={ "ActivationRange": "", @@ -173,11 +133,6 @@ _global_script_class_icons={ "GameObjectScanner": "", "GameUI": "", "GameWorld": "", -"GotmDebug": "", -"GotmFile": "", -"GotmLobby": "", -"GotmLobbyFetch": "", -"GotmUser": "", "MapTiles": "", "Occluder": "", "POI": "", @@ -186,10 +141,7 @@ _global_script_class_icons={ "ProbeArea": "", "ProbeElectric": "", "ResourceQueue": "", -"UICommand": "", -"_GotmDebugImpl": "", -"_GotmImpl": "", -"_GotmImplUtility": "" +"UICommand": "" } [application] @@ -205,7 +157,6 @@ config/icon="res://icon.png" Music="*res://Scenes/Global/Music.tscn" Multiplayer="*res://Scenes/Global/Multiplayer.gd" SceneManager="*res://Scenes/Global/SceneManager.gd" -Gotm="*res://gotm/Gotm.gd" [display] @@ -264,6 +215,11 @@ sprint={ "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777237,"unicode":0,"echo":false,"script":null) ] } +ui_chat={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":84,"unicode":0,"echo":false,"script":null) + ] +} [layer_names]