Server generation of star system and authority for gravity

This commit is contained in:
2025-11-18 21:58:14 +01:00
parent f8d140a9b0
commit e271c59837
10 changed files with 137 additions and 28 deletions

View File

@ -0,0 +1,22 @@
[gd_scene load_steps=3 format=3 uid="uid://b7bh45nrtdom5"]
[ext_resource type="Script" uid="uid://b2hb3bwrlh40c" path="res://scenes/celestial_bodies/barycenter.gd" id="1_e776o"]
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_e776o"]
properties/0/path = NodePath(".:linear_velocity")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath(".:position")
properties/1/spawn = true
properties/1/replication_mode = 1
[node name="Barycenter" type="RigidBody3D" unique_id=1389317234]
script = ExtResource("1_e776o")
metadata/_custom_type_script = "uid://wlm40n8ywr"
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=717759965]
replication_config = SubResource("SceneReplicationConfig_e776o")
[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="." unique_id=2061784354]
_spawnable_scenes = PackedStringArray("uid://dv18eg4xrlefe")
spawn_path = NodePath("..")

View File

@ -2,11 +2,12 @@ class_name CelestialBody extends OrbitalBody3D
# --- Set in corresponding scene ---
# var auto_proxy_gravity = false
@export var radius: float = 100.0
@export var radius: float = 100.0:
set(value):
radius = value
_set_radi()
func set_radius(value: float):
radius = value
func _set_radi():
if $Surface.mesh is SphereMesh:
$Surface.mesh.radius = radius
$Surface.mesh.height = radius * 2.0

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=5 format=3 uid="uid://dv18eg4xrlefe"]
[gd_scene load_steps=6 format=3 uid="uid://dv18eg4xrlefe"]
[ext_resource type="Script" uid="uid://dok35h0q4pseh" path="res://scenes/celestial_bodies/celestial_body.gd" id="1_uxu4s"]
[ext_resource type="Material" uid="uid://de0xnmjf12ted" path="res://scenes/celestial_bodies/materials/sun_mat.tres" id="2_vi0nt"]
@ -11,18 +11,38 @@ height = 4000.0
[sub_resource type="SphereShape3D" id="SphereShape3D_uxu4s"]
[node name="CelestialBody" type="RigidBody3D"]
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_vi0nt"]
properties/0/path = NodePath(".:position")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath(".:rotation")
properties/1/spawn = true
properties/1/replication_mode = 1
properties/2/path = NodePath(".:linear_velocity")
properties/2/spawn = true
properties/2/replication_mode = 1
properties/3/path = NodePath(".:angular_velocity")
properties/3/spawn = true
properties/3/replication_mode = 1
properties/4/path = NodePath(".:radius")
properties/4/spawn = true
properties/4/replication_mode = 1
[node name="CelestialBody" type="RigidBody3D" unique_id=345490070]
script = ExtResource("1_uxu4s")
auto_proxy_gravity = false
metadata/_custom_type_script = "uid://dok35h0q4pseh"
[node name="Surface" type="MeshInstance3D" parent="."]
[node name="Surface" type="MeshInstance3D" parent="." unique_id=193823349]
mesh = SubResource("SphereMesh_vi0nt")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=232085687]
shape = SubResource("SphereShape3D_uxu4s")
[node name="OmniLight3D" type="OmniLight3D" parent="."]
[node name="OmniLight3D" type="OmniLight3D" parent="." unique_id=1965995953]
light_color = Color(0.958646, 0.7997282, 0.55087835, 1)
omni_range = 200000.0
omni_attenuation = 2.0
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=2090029903]
replication_config = SubResource("SceneReplicationConfig_vi0nt")

View File

@ -1,11 +1,14 @@
extends Node
var port = 42069
var default_ip = "127.0.0.1"
func create_server() -> void:
print(multiplayer.multiplayer_peer)
print("Starting Server on port %d..." % port)
var peer = ENetMultiplayerPeer.new()
# Ensure we disconnect old signals if any
_disconnect_signals()
setup_connections()
var error = peer.create_server(port)
@ -14,37 +17,66 @@ func create_server() -> void:
return
multiplayer.multiplayer_peer = peer
print("Server Unique ID: ", multiplayer.get_unique_id())
func create_client() -> void:
func create_client(ip: String = "") -> void:
var target_ip = ip if not ip.is_empty() else default_ip
print("Connecting to Server at %s:%d..." % [target_ip, port])
_disconnect_signals()
setup_connections()
var peer = ENetMultiplayerPeer.new()
var error = peer.create_client("127.0.0.1", port)
var error = peer.create_client(target_ip, port)
if error:
push_error(error)
return
multiplayer.multiplayer_peer = peer
print("Client Unique ID: ", multiplayer.get_unique_id())
print("Client waiting for connection...")
func close_connection():
if multiplayer.multiplayer_peer:
multiplayer.multiplayer_peer.close()
multiplayer.multiplayer_peer = null
print("Connection closed.")
_disconnect_signals()
func setup_connections():
multiplayer.peer_connected.connect(on_peer_connected)
multiplayer.peer_disconnected.connect(on_peer_disconnected)
multiplayer.connected_to_server.connect(on_connected_to_server)
if not multiplayer.peer_connected.is_connected(on_peer_connected):
multiplayer.peer_connected.connect(on_peer_connected)
if not multiplayer.peer_disconnected.is_connected(on_peer_disconnected):
multiplayer.peer_disconnected.connect(on_peer_disconnected)
if not multiplayer.connected_to_server.is_connected(on_connected_to_server):
multiplayer.connected_to_server.connect(on_connected_to_server)
if not multiplayer.server_disconnected.is_connected(on_server_disconnected):
multiplayer.server_disconnected.connect(on_server_disconnected)
func _disconnect_signals():
if multiplayer.peer_connected.is_connected(on_peer_connected):
multiplayer.peer_connected.disconnect(on_peer_connected)
if multiplayer.peer_disconnected.is_connected(on_peer_disconnected):
multiplayer.peer_disconnected.disconnect(on_peer_disconnected)
if multiplayer.connected_to_server.is_connected(on_connected_to_server):
multiplayer.connected_to_server.disconnect(on_connected_to_server)
if multiplayer.server_disconnected.is_connected(on_server_disconnected):
multiplayer.server_disconnected.disconnect(on_server_disconnected)
func on_peer_connected(peer_id: int) -> void:
print("Peer %s recieved connection: %s" % [multiplayer.get_unique_id(), peer_id])
# For each peer that connects, we put them in the queue to spawn
print("Peer %s received connection: %s" % [multiplayer.get_unique_id(), peer_id])
if multiplayer.is_server():
GameManager.queue_spawn_player(peer_id)
func on_peer_disconnected(peer_id: int) -> void:
print("Peer %s lost connection to: %s" % [multiplayer.get_unique_id(), peer_id])
print(multiplayer.get_peers())
# TODO: GameManager should cleanup the player's pawn
func on_connected_to_server() -> void:
print("%s connected to server!" % multiplayer.get_unique_id())
# If we are in the main menu, this is the trigger to switch scenes
if get_tree().current_scene.name == "MainMenu":
get_tree().change_scene_to_file("res://main.tscn")
func on_server_disconnected() -> void:
print("Disconnected from server.")
get_tree().change_scene_to_file("res://scenes/UI/main_menu.tscn")

View File

@ -86,6 +86,7 @@ func _update_mass_and_inertia():
func _integrate_forces(state: PhysicsDirectBodyState3D):
if not is_multiplayer_authority(): return
# Safety Check for Division by Zero
if mass <= 0.0:
accumulated_force = Vector3.ZERO

View File

@ -4,16 +4,33 @@ extends Node3D
@export_group("System Metadata")
@export var system_name: String = "Kepler-186"
@export var system_seed: int = 0
@export var galactic_coordinates: Vector2i = Vector2i.ZERO
var system_data: SystemData
func _ready():
# 1. Create the generator tool.
var generator = StarSystemGenerator.new()
if multiplayer.is_server():
if system_seed == 0:
system_seed = randi()
seed(system_seed)
print("StarSystem (Server): Generating system with seed: %d" % system_seed)
var generator = StarSystemGenerator.new()
system_data = generator.generate(self)
# At this point, the generator has added children to 'self'.
# Because we have a MultiplayerSpawner watching 'self', these new children
# will automatically be replicated to connected clients!
else:
print("StarSystem (Client): Waiting for planets from server...")
# The client does NOT generate. It just waits for the Spawner to do its job.
# We can reconstruct 'system_data' by scanning children if needed,
# or just let GameManager find them via 'get_children()'.
# 2. Tell the generator to build the system within this StarSystem node.
system_data = generator.generate(self)
# 3. Register the completed system with the GameManager.
GameManager.register_star_system(self)

View File

@ -0,0 +1,15 @@
[gd_scene load_steps=3 format=3 uid="uid://b554pkth6hox4"]
[ext_resource type="Script" uid="uid://bkcouefvi7iup" path="res://scripts/star_system.gd" id="1_gbrlo"]
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_gbrlo"]
[node name="StarSystem" type="Node3D" unique_id=1547322980]
script = ExtResource("1_gbrlo")
[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="." unique_id=1117979460]
_spawnable_scenes = PackedStringArray("uid://dv18eg4xrlefe", "uid://b7bh45nrtdom5", "uid://bkwogkfqk2uxo")
spawn_path = NodePath("..")
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=801189521]
replication_config = SubResource("SceneReplicationConfig_gbrlo")

View File

@ -11,6 +11,7 @@ const MAX_PLANETS = 8
const MAX_MOONS_PER_PLANET = 5
const ORBIT_SAFETY_FACTOR = 5
var BarycenterScene: PackedScene = preload("res://scenes/celestial_bodies/barycenter.tscn")
var CelestialBodyScene: PackedScene = preload("res://scenes/celestial_bodies/celestial_body.tscn")
func generate(star_system: StarSystem) -> SystemData:
@ -20,7 +21,7 @@ func generate(star_system: StarSystem) -> SystemData:
system_data.star = star
star.name = "Star"
star.set_radius(2000.0)
star.radius = 2000.0
star.base_mass = STAR_MASS
star_system.add_child(star)
@ -28,12 +29,12 @@ func generate(star_system: StarSystem) -> SystemData:
var current_orbit_radius = 15000.0
for i in range(num_planets):
var planet_barycenter = Barycenter.new()
var planet_barycenter = BarycenterScene.instantiate()
planet_barycenter.name = "PlanetSystem_%d" % (i + 1)
star_system.add_child(planet_barycenter)
var planet: CelestialBody = CelestialBodyScene.instantiate()
planet.set_radius(randf_range(50.0, 200.0))
planet.radius = randf_range(50.0, 200.0)
system_data.planets.append(planet)
planet.name = "Planet_%d" % (i + 1)
planet.base_mass = randf_range(PLANET_MASS * 0.2, PLANET_MASS * 5.0)
@ -69,7 +70,7 @@ func _generate_moons(planet: OrbitalBody3D, planet_barycenter: Barycenter, syste
for i in range(num_moons):
var moon = CelestialBodyScene.instantiate()
moon.set_radius(10.0)
moon.radius = 10.0
system_data.moons.append(moon)
planet_barycenter.add_child(moon)
planet_barycenter.recalculate_total_mass()