diff --git a/Actors/Components/ActivationRange.gd b/Actors/Components/ActivationRange.gd index 147cef6..3c01ad3 100644 --- a/Actors/Components/ActivationRange.gd +++ b/Actors/Components/ActivationRange.gd @@ -2,8 +2,8 @@ extends Area2D class_name ActivationRange -signal player_entered() -signal player_left() +signal player_entered(player) +signal player_left(player) func _ready(): connect("body_entered", self, "_body_entered") @@ -14,8 +14,8 @@ func in_range(): func _body_entered(body: Node): if body == $"/root/scene/world".player: - emit_signal("player_entered") + emit_signal("player_entered", body) func _body_left(body: Node): if body == $"/root/scene/world".player: - emit_signal("player_left") + emit_signal("player_left", body) diff --git a/Actors/Components/PowerManager.gd b/Actors/Components/PowerManager.gd index 1fba19e..14e9a4f 100644 --- a/Actors/Components/PowerManager.gd +++ b/Actors/Components/PowerManager.gd @@ -19,14 +19,10 @@ var powered = false setget set_powered func get_wired() -> bool: return socket != null -func set_powered(val: bool) -> void: +remotesync func set_powered(val: bool) -> void: var current = powered powered = val if current and not val: emit_signal("power_disconnected") elif not current and val: emit_signal("power_connected") - -func _physics_process(_delta: float) -> void: - if wired: - pass diff --git a/Actors/Meta/POI/POI.gd b/Actors/Meta/POI/POI.gd new file mode 100644 index 0000000..cc63181 --- /dev/null +++ b/Actors/Meta/POI/POI.gd @@ -0,0 +1,36 @@ +tool + +extends Node2D + +class_name POI + +enum POIType { + Null, + SpawnPoint +} + +enum POIClass { + Null, + Player +} + +export(POIType) var poitype = POIType.Null +export(POIClass) var poiclass = POIClass.Null + +func _draw(): + if Engine.editor_hint: + match poitype: + POIType.SpawnPoint: + match poiclass: + POIClass.Player: + draw_arc(Vector2.ZERO, 10, 0, PI*2, 16, Color.red, 2) + +func serialize(): + return { + "poitype": poitype, + "poiclass": poiclass + } + +func deserialize(data): + poitype = data["poitype"] + poiclass = data["poiclass"] diff --git a/Actors/Meta/POI/POI.tscn b/Actors/Meta/POI/POI.tscn new file mode 100644 index 0000000..52b14a5 --- /dev/null +++ b/Actors/Meta/POI/POI.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://Actors/Meta/POI/POI.gd" type="Script" id=1] + +[node name="NullPOI" type="Node2D"] +position = Vector2( 208, 256 ) +script = ExtResource( 1 ) +poitype = 1 +poiclass = 1 diff --git a/Actors/Meta/POI/Spawnpoints/Player.gd b/Actors/Meta/POI/Spawnpoints/Player.gd deleted file mode 100644 index f997847..0000000 --- a/Actors/Meta/POI/Spawnpoints/Player.gd +++ /dev/null @@ -1,12 +0,0 @@ -tool - -extends Node2D - -class_name SpawnpointPlayer - -var poitype = POIData.POIType.SpawnPoint -var poiclass = POIData.POIClass.Player - -func _draw(): - if Engine.editor_hint: - draw_arc(Vector2.ZERO, 10, 0, PI*2, 16, Color.red) diff --git a/Actors/Objects/Computer/Computer.gd b/Actors/Objects/Computer/Computer.gd index 32d4975..421b311 100644 --- a/Actors/Objects/Computer/Computer.gd +++ b/Actors/Objects/Computer/Computer.gd @@ -102,3 +102,13 @@ func _power_status_changed(powered: bool) -> void: $ScreenAnimation.play("on") else: $ScreenAnimation.play("off") + +func serialize(): + return { + "direction": direction, + "computer_type": computer_type + } + +func deserialize(data): + set_direction(data["direction"]) + set_type(data["computer_type"]) diff --git a/Actors/Objects/Door/Door.gd b/Actors/Objects/Door/Door.gd index ad20a6b..d42a35d 100644 --- a/Actors/Objects/Door/Door.gd +++ b/Actors/Objects/Door/Door.gd @@ -14,33 +14,40 @@ onready var manager = $PowerManager as PowerManager signal changed(open) func _ready(): - if interlockTargetPath != null: - interlockTarget = get_node_or_null(interlockTargetPath) - if not Engine.editor_hint: - activationRange.visible = true + if is_network_master(): + if interlockTargetPath != null: + interlockTarget = get_node_or_null(interlockTargetPath) + if not Engine.editor_hint: + activationRange.visible = true -func set_open(open: bool): +master func set_open(open: bool): if not manager: return manager.power_usage = active_usage if manager.powered: if open: - $Sprite.play("open") if interlockTarget != null: interlockTarget.set_open(false) - else: - $Sprite.play("close") + rpc("anim_open", open) + +remotesync func anim_open(open: bool): + if open: + $Sprite.play("open") + else: + $Sprite.play("close") func _animation_finished(): - if manager: - manager.power_usage = idle_usage + if is_network_master(): + if manager: + manager.power_usage = idle_usage + if $Sprite.animation == "open": + # Start timer for auto-close + $Timer.start() if $Sprite.animation == "open": # Disable collider collision_layer = 16 collision_mask = 16 emit_signal("changed", true) - # Start timer for auto-close - $Timer.start() else: # Enable collider collision_mask = 1 @@ -52,7 +59,13 @@ func _input_event(_viewport, event, _shape_idx): if event is InputEventMouseButton and event.pressed: # Must be in activation range if activationRange.in_range(): - set_open($Sprite.animation == "close") + rpc("set_open", $Sprite.animation == "close") -func _close_timer_triggered(): - $Sprite.play("close") +master func _close_timer_triggered(): + rpc("set_open", false) + +func serialize(): + return {} + +func deserialize(data): + pass diff --git a/Actors/Objects/ElectricSocket/ElectricSocket.gd b/Actors/Objects/ElectricSocket/ElectricSocket.gd index 0730a7b..cd753d6 100644 --- a/Actors/Objects/ElectricSocket/ElectricSocket.gd +++ b/Actors/Objects/ElectricSocket/ElectricSocket.gd @@ -62,3 +62,17 @@ func refresh_sprite() -> void: socket.material.set_shader_param("cable_color", sink_color) Flow.BIDIRECTIONAL: socket.material.set_shader_param("cable_color", bidirectional_color) + +func serialize(): + return { + "direction": direction, + "flow": flow, + "network": "", #TODO + "connections": [] #TODO + } + +func deserialize(data): + set_direction(data["direction"]) + set_flow(data["flow"]) + #TODO Connections + #TODO Network diff --git a/Actors/Objects/Engine/Engine.gd b/Actors/Objects/Engine/Engine.gd index 5326b5c..d06e48b 100644 --- a/Actors/Objects/Engine/Engine.gd +++ b/Actors/Objects/Engine/Engine.gd @@ -54,3 +54,13 @@ func _input_event(_viewport, event, _shape_idx): if activationRange.in_range(): # TODO pass + +func serialize(): + return { + "direction": direction, + "strength": strength + } + +func deserialize(data): + set_direction(data["direction"]) + set_strength(data["strength"]) diff --git a/Actors/Objects/Lightbulb/Lightbulb.gd b/Actors/Objects/Lightbulb/Lightbulb.gd index abe5412..7a1ed4c 100644 --- a/Actors/Objects/Lightbulb/Lightbulb.gd +++ b/Actors/Objects/Lightbulb/Lightbulb.gd @@ -17,11 +17,11 @@ func _ready(): activationRange.visible = true refresh_sprite() -func set_direction(dir): +remotesync func set_direction(dir): direction = dir refresh_sprite() -func set_lit(val): +remotesync func set_lit(val): lit = val update_light() refresh_sprite() @@ -35,7 +35,7 @@ func refresh_sprite(): match direction: Direction.DOWN: $light.region_rect.position = Vector2(32, lit_offset) - rot =0 + rot = 0 Direction.UP: $light.region_rect.position = Vector2(0, lit_offset) rot = PI @@ -47,14 +47,13 @@ func refresh_sprite(): rot = PI/2 $Light2D.rotation = rot $ActivationRange.rotation = rot - func _input_event(_viewport, event, _shape_idx): if Engine.editor_hint: return if event is InputEventMouseButton and event.pressed: if activationRange.in_range(): - set_lit(!lit) + rpc("set_lit", !lit) func _power_status_changed(_powered: bool) -> void: update_light() @@ -62,3 +61,13 @@ func _power_status_changed(_powered: bool) -> void: func update_light(): $Light2D.enabled = lit and (manager != null and manager.powered) + +func serialize(): + return { + "direction": direction, + "lit": lit + } + +func deserialize(data): + set_direction(data["direction"]) + set_lit(data["lit"]) diff --git a/Actors/Objects/PowerStorage/PowerStorage.gd b/Actors/Objects/PowerStorage/PowerStorage.gd index e9687ed..1656b77 100644 --- a/Actors/Objects/PowerStorage/PowerStorage.gd +++ b/Actors/Objects/PowerStorage/PowerStorage.gd @@ -80,3 +80,15 @@ func set_max_charge(val: float) -> void: func set_charge(val: float) -> void: current_charge = val $Control/PowerUI.set_current_charge(current_charge) + +func serialize(): + return { + "current_charge": current_charge, + "max_charge_rate": max_charge_rate, + "max_discharge_rate": max_discharge_rate + } + +func deserialize(data): + set_charge(data["current_charge"]) + set_max_charge(data["max_charge_rate"]) + set_max_discharge(data["max_discharge_rate"]) diff --git a/Actors/Objects/Scanner/Scanner.gd b/Actors/Objects/Scanner/Scanner.gd index ab760b7..67d30bd 100644 --- a/Actors/Objects/Scanner/Scanner.gd +++ b/Actors/Objects/Scanner/Scanner.gd @@ -2,3 +2,8 @@ extends StaticBody2D class_name GameObjectScanner +func serialize(): + return {} + +func deserialize(data): + pass diff --git a/Actors/Player/Player.gd b/Actors/Player/Player.gd index 9e6703a..29fdbe3 100644 --- a/Actors/Player/Player.gd +++ b/Actors/Player/Player.gd @@ -5,11 +5,17 @@ const EPSILON = 0.1 const MAX_STAMINA = 3.0 const BOOST_COEFF = 50.0 const STAMINA_RECOVER_RATE = 0.3 +const NET_KEY_TRANSFORM_DELAY = 0.2 var velocity = Vector2.ZERO var grip = 1.0 var stamina = MAX_STAMINA var speed_boost = 0 +var transform_update_remaining = 0.0 + +puppet var pup_motion = Vector2.ZERO +puppet var pup_velocity = Vector2.ZERO +puppet var pup_transform = Transform() onready var scene = $"/root/scene" onready var world = $"/root/scene/world" @@ -21,33 +27,48 @@ func _ready(): $Camera.current = is_controlled func _physics_process(delta): - var motion = Vector2( - Input.get_action_strength("ui_right")-Input.get_action_strength("ui_left"), - Input.get_action_strength("ui_down")-Input.get_action_strength("ui_up")) + var motion = Vector2.ZERO + if is_network_master(): + motion = Vector2( + Input.get_action_strength("ui_right")-Input.get_action_strength("ui_left"), + Input.get_action_strength("ui_down")-Input.get_action_strength("ui_up")) + + # Check sprinting + var speed = BASE_SPEED + if Input.is_action_pressed("sprint"): + if motion.length() > EPSILON and stamina > 0: + speed_boost += BOOST_COEFF * delta * ease(stamina/MAX_STAMINA, 1.1) + stamina -= delta + update() + else: + if stamina < MAX_STAMINA: + stamina += delta * STAMINA_RECOVER_RATE + update() + + # Apply friction to speed boost and the boost itself, if any + if speed_boost > 0: + speed_boost /= 2 + speed *= 1.0 + speed_boost + if speed_boost < EPSILON: + speed_boost = 0 + + # Set velocity + velocity = velocity * (1.0-grip) + motion.clamped(1.0) * speed * grip + rset("pup_motion", motion) + rset("pup_velocity", velocity) + rset("pup_transform", global_transform) + else: + velocity = pup_velocity + motion = pup_motion + if transform_update_remaining <= 0.0: + transform_update_remaining = NET_KEY_TRANSFORM_DELAY + global_transform = pup_transform + else: + transform_update_remaining -= delta + if motion.length() > EPSILON: $Sprite/AnimationTree.set("parameters/direction/blend_position", motion) - # Check sprinting - var speed = BASE_SPEED - if Input.is_action_pressed("sprint"): - if motion.length() > EPSILON and stamina > 0: - speed_boost += BOOST_COEFF * delta * ease(stamina/MAX_STAMINA, 1.1) - stamina -= delta - update() - else: - if stamina < MAX_STAMINA: - stamina += delta * STAMINA_RECOVER_RATE - update() - - # Apply friction to speed boost and the boost itself, if any - if speed_boost > 0: - speed_boost /= 2 - speed *= 1.0 + speed_boost - if speed_boost < EPSILON: - speed_boost = 0 - - # Set velocity - velocity = velocity * (1.0-grip) + motion.clamped(1.0) * speed * grip velocity = move_and_slide(velocity) # Check what tile I'm on @@ -63,8 +84,9 @@ func set_is_controlled(val): $Camera.current = val func _draw(): - if stamina+EPSILON < MAX_STAMINA: - draw_circle_arc_poly(Vector2(-10, -30), 6, 0, stamina/MAX_STAMINA * 360, Color.orange) + if is_network_master(): + if stamina+EPSILON < MAX_STAMINA: + draw_circle_arc_poly(Vector2(-10, -30), 6, 0, stamina/MAX_STAMINA * 360, Color.orange) func draw_circle_arc_poly(center, radius, angle_from, angle_to, color): var nb_points = 32 diff --git a/Actors/Systems/Electricity/ElectricProbe.gd b/Actors/Systems/Electricity/ElectricProbe.gd index 2ba1472..81ac834 100644 --- a/Actors/Systems/Electricity/ElectricProbe.gd +++ b/Actors/Systems/Electricity/ElectricProbe.gd @@ -8,13 +8,13 @@ var neighbours = [] var network: PowerNetwork = null -func _ready(): +master func _ready(): if network == null: network = PowerNetwork.new() network.add_node(self) $"/root/scene/systems".add_child(network, true) -func _physics_process(_delta): +master func _physics_process(_delta): if PowerNetwork.DEBUG: update() @@ -25,13 +25,13 @@ func _draw(): var delta = (neighbour.global_position - global_position) / global_scale draw_line(center, delta + center, network.debugColor, 2) -func _got_neighbour(area: Area2D): +master func _got_neighbour(area: Area2D): if area == self: return if area.network == null: area.network = network - network.add_node(area) + network.rpc("add_node", area) elif area.network != network: # Merge networks - network.join(area.network) + network.rpc("join", area.network) neighbours.push_back(area) diff --git a/Actors/Systems/Electricity/PowerNetwork.gd b/Actors/Systems/Electricity/PowerNetwork.gd index 0343cc3..e1a91c7 100644 --- a/Actors/Systems/Electricity/PowerNetwork.gd +++ b/Actors/Systems/Electricity/PowerNetwork.gd @@ -2,7 +2,7 @@ extends Node class_name PowerNetwork -const DEBUG = false +const DEBUG = true var nodes = [] var sockets = [] @@ -16,12 +16,12 @@ func _ready(): name = "PowerNetwork" debugColor = Color.from_hsv(randf(), 0.8, 0.8) -func add_node(node) -> void: +remotesync func add_node(node) -> void: nodes.append(node) if "connections" in node: sockets.append(node) -func remove_node(node) -> void: +remotesync func remove_node(node) -> void: var node_idx = nodes.find(node) if node_idx >= 0: nodes.remove(node_idx) @@ -31,7 +31,7 @@ func remove_node(node) -> void: # Do other splitting here node.network = null -func join(network) -> void: +remotesync func join(network) -> void: for node in network.nodes: nodes.append(node) node.network = self @@ -42,6 +42,8 @@ func join(network) -> void: network.queue_free() func _physics_process(_delta: float) -> void: + if not is_network_master(): + return # Recalculate power availability and usage total_source = 0 total_usage = 0 @@ -70,9 +72,11 @@ func _physics_process(_delta: float) -> void: if sink.power_usage > 0: if available_supply > sink.power_usage: available_supply -= sink.power_usage - sink.powered = true + if not sink.powered: + sink.rpc("set_powered", true) else: - sink.powered = false + if sink.powered: + sink.rpc("set_powered", false) # Update available power to sinks for sink in sinks: sink.available = available_supply diff --git a/Classes/POI.gd b/Classes/POI.gd deleted file mode 100644 index a696f29..0000000 --- a/Classes/POI.gd +++ /dev/null @@ -1,9 +0,0 @@ -class_name POIData - -enum POIType { - SpawnPoint -} - -enum POIClass { - Player -} diff --git a/Scenes/Game.gd b/Scenes/Game.gd index 532f944..2c213c2 100644 --- a/Scenes/Game.gd +++ b/Scenes/Game.gd @@ -5,9 +5,39 @@ class_name GameInstance onready var ui = $CanvasLayer/ui onready var world = $world onready var systems = $systems +onready var netgame = $"/root/Multiplayer" -func _ready(): +func _ready() -> void: ui.connect("command", world, "process_command") + if netgame.hosting: + world.load_map(netgame.get_current_map()) + rpc("spawn_player", 1) + else: + world.load_map(GameWorld.Map.EMPTY) + rpc_id(1, "send_map") + yield(world.map, "map_received") + rpc_id(1, "ready_to_spawn") + +master func send_map() -> void: + var id = get_tree().get_rpc_sender_id() + print("sending map data to ", id) + world.map.send_data(id) + +master func ready_to_spawn() -> void: + var id = get_tree().get_rpc_sender_id() + print(id, " is ready to spawn players") + + # Tell him everyone to spawn + var players = $world/players.get_children() + for player in players: + rpc_id(id, "spawn_player", player.get_network_master()) + + # Then spawn him as well + rpc("spawn_player", id) + +remotesync func spawn_player(id): + print("must spawn ", id) + world.spawn_player(id, multiplayer.get_network_unique_id() == id) func process_command(cmd: UICommand): match cmd.cmd_type: @@ -15,3 +45,4 @@ func process_command(cmd: UICommand): world.map.ship_speed = cmd.cmd_args[0] UICommand.CommandType.SetShipDirection: world.map.ship_direction = cmd.cmd_args[0] + diff --git a/Scenes/Game.tscn b/Scenes/Game.tscn index 1521c3c..f818fd9 100644 --- a/Scenes/Game.tscn +++ b/Scenes/Game.tscn @@ -12,7 +12,6 @@ script = ExtResource( 5 ) [node name="world" type="Node2D" parent="."] scale = Vector2( 2, 2 ) script = ExtResource( 4 ) -mapToLoad = 1 [node name="players" type="Node2D" parent="world"] diff --git a/Scenes/Global/Multiplayer.gd b/Scenes/Global/Multiplayer.gd index 888aba5..05112b1 100644 --- a/Scenes/Global/Multiplayer.gd +++ b/Scenes/Global/Multiplayer.gd @@ -18,9 +18,12 @@ var ms_active = false var ms_key = "" var server_name = "" +var hosting = false + export var player_name = "" var player_info = {} +var round_info = {} onready var scene_manager = $"/root/SceneManager" @@ -84,10 +87,16 @@ func host(): return get_tree().network_peer = peer print("Hosting") + hosting = true server_name = player_name + "'s server" - player_info[1] = { name=player_name } + player_info[1] = { "name": player_name } + round_info = { "map": "odyssey" } - scene_manager.load_scene_with_args("res://Scenes/Game.tscn", []) + scene_manager.loading_text = null + + scene_manager.load_scene("res://Scenes/Game.tscn", [ + "res://Scenes/Maps/odyssey.tscn" + ]) # Add to master server create_ms_entry() @@ -121,8 +130,7 @@ func leave(): func _player_connected(id): rpc_id(id, "register_player", player_name) if get_tree().is_network_server(): - pass - #rpc_id(id, "spawn_players", mapLoader.map.all_players()) + rpc_id(id, "_handshake", { "round": round_info, "players": player_info }) func _player_disconnected(id): print(player_info[id].name, " (", id, ") disconnected") @@ -130,7 +138,8 @@ func _player_disconnected(id): func _connected_ok(): print("Connected to server") - scene_manager.loading_text = "Connected to server" + scene_manager.loading_text = null + scene_manager.load_scene("res://Scenes/Game.tscn", []) func _server_disconnected(): print("Disconnected from server") @@ -143,12 +152,9 @@ remote func register_player(username: String): player_info[id] = { name=username } print(player_info[id].name, " (", id, ") connected") -remote func spawn_players(players): - for player_id in players: - pass - #mapLoader.map.spawn_player(player_id) - # Spawn myself as well - #mapLoader.map.rpc("spawn_player", get_tree().network_peer.get_unique_id()) +remote func _handshake(infos): + round_info = infos["round"] + player_info = infos["players"] func _ms_request(endpoint: String, data): var http_request = HTTPRequest.new() @@ -203,3 +209,12 @@ func _notification(what): if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST: leave() yield(self, "left") + +func get_current_map(): + match round_info.map: + "odyssey": + return GameWorld.Map.ODYSSEY + "runtime": + return GameWorld.Map.RUNTIME + _: + return GameWorld.Map.EMPTY diff --git a/Scenes/Global/SceneManager.gd b/Scenes/Global/SceneManager.gd index ea85dda..26c6230 100644 --- a/Scenes/Global/SceneManager.gd +++ b/Scenes/Global/SceneManager.gd @@ -1,29 +1,40 @@ extends Node -var queue = null +var queue = ResourceQueue.new() var target_scene = null var loading_text = null var loader = preload("res://Scenes/Loader.tscn") -func enter_loader(): +func _ready() -> void: + queue.start() + +func enter_loader() -> void: get_tree().change_scene_to(loader) -func load_scene_with_args(scene_path: String, _args: Array): - queue = ResourceQueue.new() - queue.start() +func load_scene(scene_path: String, dependencies: Array) -> void: target_scene = scene_path queue.queue_resource(scene_path) + for dep in dependencies: + queue.queue_resource(dep) -func _physics_process(delta): - if queue != null and target_scene != null: - if queue.is_ready(target_scene): +func _physics_process(_delta: float) -> void: + if target_scene != null: + var remaining = queue.pending.size() + for path in queue.pending: + if queue.is_ready(path): + remaining -= 1 + if remaining == 0: get_tree().change_scene_to(queue.get_resource(target_scene)) - queue = null target_scene = null -func get_progress(): +func get_progress() -> String: if loading_text != null: return loading_text - if queue != null and target_scene != null: - return "Loading scene (" + str(queue.get_progress(target_scene)) + ")" + var count = queue.pending.size() + if count == 0: + return "Reticulating splines" + var current = 0 + for path in queue.pending: + current += queue.get_progress(path) + return "Loading scene (" + str(round(current/count*100)) + "%)" diff --git a/Scenes/Map.gd b/Scenes/Map.gd index fe12e87..588dfd3 100644 --- a/Scenes/Map.gd +++ b/Scenes/Map.gd @@ -3,6 +3,8 @@ extends Node2D class_name GameMap +signal map_received() + var ship_direction = 0 var ship_speed = 0 @@ -31,10 +33,18 @@ func _ready(): if Engine.editor_hint: return $editor.queue_free() - set_unlit(false) + set_unlit(true) + + if not is_network_master(): + return + + # Run special tiling + $walls.run_conversions() # Electricity setup make_electric_probes($cables, "Wire") + + print(serialize()) func _process(delta: float): if Engine.editor_hint: @@ -53,6 +63,71 @@ func _process(delta: float): $deepspace.rotation = current_ship_direction-PI/2 $deepspace.region_rect.position += Vector2(sin(current_ship_direction), cos(current_ship_direction)) * current_ship_speed * delta +# Serialization / Deserialization + +func serialize() -> Dictionary: + # Get tilemap data + var tilemapdata = {} + for tilemap in tilemaps: + var data = [] + for cell in tilemap.get_used_cells(): + 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 pois = serialize_children($pois) + + return { + "tilemaps": tilemapdata, + "engines": engines, + "objects": objects, + "lights": lights, + "pois": pois + } + +func deserialize(data: Dictionary) -> void: + for tilemap in data["tilemaps"]: + var tilemap_node = get_node(tilemap) as TileMap + for tile in data["tilemaps"][tilemap]: + tilemap_node.set_cellv(tile[0], tile[1]) + tilemap_node.update_bitmask_region() + tilemap_node.update_dirty_quadrants() + deserialize_children($engines, data["engines"]) + deserialize_children($objects, data["objects"]) + deserialize_children($lights, data["lights"]) + deserialize_children($pois, data["pois"]) + $walls.run_conversions() + +master func send_data(id: int) -> void: + rpc_id(id, "receive_data", serialize()) + +puppet func receive_data(data: Dictionary) -> void: + deserialize(data) + print("Received map data from master") + emit_signal("map_received") + +func serialize_children(node: Node) -> Dictionary: + var data = {} + for child in node.get_children(): + data[child.name] = { + "filename": child.filename, + "data": child.serialize(), + "transform": child.transform + } + return data + +func deserialize_children(node: Node, data: Dictionary) -> 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 + node_scene.deserialize(node_data.data) + node.add_child(node_scene, true) + # Lighting func set_unlit(val: bool): diff --git a/Scenes/Maps/Objects.gd b/Scenes/Maps/Objects.gd deleted file mode 100644 index 7080026..0000000 --- a/Scenes/Maps/Objects.gd +++ /dev/null @@ -1,17 +0,0 @@ -extends TileMap - -const objects = { - "Door": preload("res://Actors/Objects/Door/Door.tscn") -} - -func _ready(): - for cell in get_used_cells(): - var id = get_cellv(cell) - var name = tile_set.tile_get_name(id) - if objects.has(name): - var obj = objects[name].instance() as Node2D - add_child(obj) - obj.transform.origin = map_to_world(cell) - else: - print("Placed object tile ", name, " at ", cell, " but has no object associated!") - set_cellv(cell, -1) diff --git a/Scenes/Maps/empty.tscn b/Scenes/Maps/empty.tscn new file mode 100644 index 0000000..2b0713e --- /dev/null +++ b/Scenes/Maps/empty.tscn @@ -0,0 +1,96 @@ +[gd_scene load_steps=10 format=2] + +[ext_resource path="res://Graphics/tgstation/walls.tres" type="TileSet" id=1] +[ext_resource path="res://Graphics/tgstation/1x1.tres" type="TileSet" id=2] +[ext_resource path="res://Scenes/Rendering/MapTiles.gd" type="Script" id=3] +[ext_resource path="res://Scenes/Map.gd" type="Script" id=4] +[ext_resource path="res://Graphics/space.png" type="Texture" id=7] +[ext_resource path="res://Graphics/tgstation/floor.tres" type="TileSet" id=9] +[ext_resource path="res://Graphics/tgstation/base.tres" type="TileSet" id=11] +[ext_resource path="res://Graphics/tgstation/cables.tres" type="TileSet" id=13] + +[sub_resource type="CanvasItemMaterial" id=1] +light_mode = 1 + +[node name="map" type="Node2D"] +script = ExtResource( 4 ) + +[node name="darkness" type="CanvasModulate" parent="."] +visible = false +color = Color( 0, 0, 0, 1 ) + +[node name="editor" type="Node2D" parent="."] + +[node name="deepspace" type="Sprite" parent="."] +material = SubResource( 1 ) +texture = ExtResource( 7 ) +region_enabled = true +region_rect = Rect2( 0, 0, 10000, 10000 ) +__meta__ = { +"_edit_group_": true, +"_edit_lock_": true +} + +[node name="base" type="TileMap" parent="."] +z_index = 1 +tile_set = ExtResource( 11 ) +cell_size = Vector2( 32, 32 ) +cell_quadrant_size = 32 +occluder_light_mask = -2147483647 +format = 1 + +[node name="cables" type="TileMap" parent="."] +z_index = 2 +tile_set = ExtResource( 13 ) +cell_size = Vector2( 32, 32 ) +cell_quadrant_size = 32 +occluder_light_mask = -2147483647 +format = 1 + +[node name="floor" type="TileMap" parent="."] +z_index = 3 +tile_set = ExtResource( 9 ) +cell_size = Vector2( 32, 32 ) +cell_quadrant_size = 32 +occluder_light_mask = -2147483647 +format = 1 + +[node name="walls" type="TileMap" parent="."] +z_index = 4 +tile_set = ExtResource( 1 ) +cell_size = Vector2( 32, 32 ) +cell_quadrant_size = 32 +occluder_light_mask = -2147483647 +format = 1 +script = ExtResource( 3 ) +extended_tilemap_node = NodePath("../1x1") + +[node name="1x1" type="TileMap" parent="."] +z_index = 5 +tile_set = ExtResource( 2 ) +cell_size = Vector2( 16, 16 ) +format = 1 + +[node name="engines" type="Node2D" parent="."] +modulate = Color( 0.980392, 0.980392, 0.980392, 1 ) +__meta__ = { +"_edit_group_": true, +"_edit_lock_": true +} + +[node name="objects" type="Node2D" parent="."] +z_index = 10 +__meta__ = { +"_editor_description_": "" +} + +[node name="lights" type="Node2D" parent="."] +modulate = Color( 0.980392, 0.980392, 0.980392, 1 ) +z_index = 11 +__meta__ = { +"_edit_group_": true, +"_edit_lock_": true +} + +[node name="pois" type="Node2D" parent="."] +z_index = 999 diff --git a/Scenes/Maps/odyssey.gd b/Scenes/Maps/odyssey.gd deleted file mode 100644 index a2b9ff4..0000000 --- a/Scenes/Maps/odyssey.gd +++ /dev/null @@ -1,9 +0,0 @@ -extends GameMap - -func _ready(): - tilemaps = [ - $base, - $cables, - $floor, - $walls - ] diff --git a/Scenes/Maps/odyssey.tscn b/Scenes/Maps/odyssey.tscn index ebbd860..22bb9a1 100644 --- a/Scenes/Maps/odyssey.tscn +++ b/Scenes/Maps/odyssey.tscn @@ -4,7 +4,7 @@ [ext_resource path="res://Graphics/tgstation/1x1.tres" type="TileSet" id=2] [ext_resource path="res://Scenes/Rendering/MapTiles.gd" type="Script" id=3] [ext_resource path="res://Actors/Objects/Door/Door.tscn" type="PackedScene" id=4] -[ext_resource path="res://Scenes/Maps/odyssey.gd" type="Script" id=5] +[ext_resource path="res://Scenes/Map.gd" type="Script" id=5] [ext_resource path="res://Actors/Objects/Computer/Computer.tscn" type="PackedScene" id=6] [ext_resource path="res://Graphics/space.png" type="Texture" id=7] [ext_resource path="res://Actors/Objects/Lightbulb/Lightbulb.tscn" type="PackedScene" id=8] @@ -14,7 +14,7 @@ [ext_resource path="res://Actors/Objects/PowerStorage/PowerStorage.tscn" type="PackedScene" id=12] [ext_resource path="res://Graphics/tgstation/cables.tres" type="TileSet" id=13] [ext_resource path="res://Actors/Objects/ElectricSocket/ElectricSocket.tscn" type="PackedScene" id=14] -[ext_resource path="res://Actors/Meta/POI/Spawnpoints/Player.gd" type="Script" id=15] +[ext_resource path="res://Actors/Meta/POI/POI.tscn" type="PackedScene" id=15] [sub_resource type="CanvasItemMaterial" id=1] light_mode = 1 @@ -152,7 +152,6 @@ interlockTargetPath = NodePath("../AirlockExt3") [node name="ControlComp" parent="objects" instance=ExtResource( 6 )] position = Vector2( 576, 256 ) direction = 0 -computer_type = 0 [node name="CommsComp" parent="objects" instance=ExtResource( 6 )] position = Vector2( 576, 224 ) @@ -542,6 +541,4 @@ direction = 2 [node name="pois" type="Node2D" parent="."] z_index = 999 -[node name="SpawnpointPlayer" type="Node2D" parent="pois"] -position = Vector2( 208, 256 ) -script = ExtResource( 15 ) +[node name="SpawnpointPlayer" parent="pois" instance=ExtResource( 15 )] diff --git a/Scenes/Maps/runtime.gd b/Scenes/Maps/runtime.gd deleted file mode 100644 index eff4d79..0000000 --- a/Scenes/Maps/runtime.gd +++ /dev/null @@ -1,4 +0,0 @@ -extends GameMap - -func _ready(): - set_unlit(true) diff --git a/Scenes/Maps/runtime.tscn b/Scenes/Maps/runtime.tscn index e1370a9..ccf96b4 100644 --- a/Scenes/Maps/runtime.tscn +++ b/Scenes/Maps/runtime.tscn @@ -4,21 +4,27 @@ [ext_resource path="res://Graphics/tgstation/1x1.tres" type="TileSet" id=2] [ext_resource path="res://Scenes/Rendering/MapTiles.gd" type="Script" id=3] [ext_resource path="res://Graphics/tgstation/cables.tres" type="TileSet" id=4] -[ext_resource path="res://Scenes/Maps/runtime.gd" type="Script" id=5] +[ext_resource path="res://Actors/Meta/POI/POI.tscn" type="PackedScene" id=5] [ext_resource path="res://Actors/Objects/Computer/Computer.tscn" type="PackedScene" id=6] [ext_resource path="res://Graphics/space.png" type="Texture" id=7] -[ext_resource path="res://Actors/Meta/POI/Spawnpoints/Player.gd" type="Script" id=8] [ext_resource path="res://Graphics/tgstation/floor.tres" type="TileSet" id=9] [ext_resource path="res://Actors/Objects/Engine/Engine.tscn" type="PackedScene" id=10] [ext_resource path="res://Graphics/tgstation/base.tres" type="TileSet" id=11] [ext_resource path="res://Actors/Objects/PowerStorage/PowerStorage.tscn" type="PackedScene" id=12] [ext_resource path="res://Actors/Objects/ElectricSocket/ElectricSocket.tscn" type="PackedScene" id=13] -[sub_resource type="CanvasItemMaterial" id=1] +[sub_resource type="GDScript" id=1] +script/source = "extends GameMap + +func _ready(): + set_unlit(true) +" + +[sub_resource type="CanvasItemMaterial" id=2] light_mode = 1 [node name="map" type="Node2D"] -script = ExtResource( 5 ) +script = SubResource( 1 ) [node name="darkness" type="CanvasModulate" parent="."] visible = false @@ -27,7 +33,7 @@ color = Color( 0, 0, 0, 1 ) [node name="editor" type="Node2D" parent="."] [node name="deepspace" type="Sprite" parent="."] -material = SubResource( 1 ) +material = SubResource( 2 ) texture = ExtResource( 7 ) region_enabled = true region_rect = Rect2( 0, 0, 10000, 10000 ) @@ -183,6 +189,7 @@ __meta__ = { [node name="pois" type="Node2D" parent="."] z_index = 999 -[node name="SpawnpointPlayer" type="Node2D" parent="pois"] -position = Vector2( 112, 272 ) -script = ExtResource( 8 ) +[node name="SpawnpointPlayer" parent="pois" instance=ExtResource( 5 )] +position = Vector2( 80, 272 ) +poitype = 1 +poiclass = 1 diff --git a/Scenes/Rendering/MapTiles.gd b/Scenes/Rendering/MapTiles.gd index cf94833..c7c321a 100644 --- a/Scenes/Rendering/MapTiles.gd +++ b/Scenes/Rendering/MapTiles.gd @@ -12,7 +12,7 @@ export var shadow_intensity = 0.2 onready var extended_tilemap = get_node(extended_tilemap_node) as TileMap -func _ready(): +func run_conversions(): # Make occluders make_occluders() diff --git a/Scenes/World.gd b/Scenes/World.gd index f9a86fb..540d075 100644 --- a/Scenes/World.gd +++ b/Scenes/World.gd @@ -2,30 +2,38 @@ extends Node2D class_name GameWorld -enum Map { RUNTIME, ODYSSEY } - -export(Map) var mapToLoad = Map.RUNTIME +enum Map { RUNTIME, ODYSSEY, EMPTY } const playerRes = preload("res://Actors/Player/Player.tscn") var map = null var player = null -func _ready(): - match mapToLoad: +onready var scene_manager = $"/root/SceneManager" + +func load_map(map_name): + match map_name: Map.RUNTIME: - map = load("res://Scenes/Maps/runtime.tscn").instance() + map = scene_manager.queue.get_resource("res://Scenes/Maps/runtime.tscn").instance() Map.ODYSSEY: - map = load("res://Scenes/Maps/odyssey.tscn").instance() + map = scene_manager.queue.get_resource("res://Scenes/Maps/odyssey.tscn").instance() + Map.EMPTY: + map = preload("res://Scenes/Maps/empty.tscn").instance() add_child(map) - player = playerRes.instance() - player.is_controlled = true - var spawnpoints = map.get_pois(POIData.POIType.SpawnPoint, POIData.POIClass.Player) + +func spawn_player(peer: int, is_current_user: bool): + var playerNode = playerRes.instance() + playerNode.set_network_master(peer, true) + playerNode.is_controlled = is_current_user + var spawnpoints = map.get_pois(POI.POIType.SpawnPoint, POI.POIClass.Player) if spawnpoints.size() > 0: - player.transform.origin = (spawnpoints[0] as Node2D).transform.origin + playerNode.transform.origin = (spawnpoints[0] as Node2D).transform.origin else: print("Map does not have Player spawnpoint POI! Spawning at origin (very bad)") - $players.add_child(player) - for tilemap in map.tilemaps: - if tilemap is MapTiles: - tilemap.set_occluder_origin(player) + $players.add_child(playerNode, true) + if is_current_user: + player = playerNode + for tilemap in map.tilemaps: + if tilemap is MapTiles: + tilemap.set_occluder_origin(playerNode) + return playerNode diff --git a/project.godot b/project.godot index 13da8e6..3d63492 100644 --- a/project.godot +++ b/project.godot @@ -74,10 +74,10 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://Scenes/Rendering/Occluder.gd" }, { -"base": "Reference", -"class": "POIData", +"base": "Node2D", +"class": "POI", "language": "GDScript", -"path": "res://Classes/POI.gd" +"path": "res://Actors/Meta/POI/POI.gd" }, { "base": "Node", "class": "PowerManager", @@ -99,11 +99,6 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://Classes/ResourceQueue.gd" }, { -"base": "Node2D", -"class": "SpawnpointPlayer", -"language": "GDScript", -"path": "res://Actors/Meta/POI/Spawnpoints/Player.gd" -}, { "base": "Reference", "class": "UICommand", "language": "GDScript", @@ -123,12 +118,11 @@ _global_script_class_icons={ "GameWorld": "", "MapTiles": "", "Occluder": "", -"POIData": "", +"POI": "", "PowerManager": "", "PowerNetwork": "", "ProbeElectric": "", "ResourceQueue": "", -"SpawnpointPlayer": "", "UICommand": "" }