J3a: the journey on a server. A server per land (Lands: the hub starts land servers on demand over a private link), the cliff tunnel online, crossings with one-time passes, shared characters that remember their land, one clock from the hub; test_net_lands

This commit is contained in:
Paul Bailey
2026-11-06 23:14:11 +00:00
parent 6544862885
commit 85bbed249b
17 changed files with 1050 additions and 28 deletions

View File

@@ -366,8 +366,9 @@ func _on_terrain_ready() -> void:
else:
pr.free()
# The journey's ways on (J1): the Valley's cliff tunnel and the Cove's sea
# cave. Single-player for now (J3 brings travel online).
if not server_mode and not menu_mode and not is_online():
# cave. On a server too (J3): the server decides the digging and the
# crossings, and every player's game has the same rock to see and walk.
if not menu_mode:
var tn := preload("res://scripts/world/tunnel.gd").new()
tn.name = "Tunnel"
add_child(tn)
@@ -698,6 +699,7 @@ func _shared_state(harvested: Dictionary, regrow: Dictionary, taken: Array, drop
"bear": bears.save_data() if bears != null else _saved_bear,
"barrow": barrow.save_data() if barrow != null else {},
"stones": stones.save_data() if stones != null else {},
"tunnel": tunnel.to_data() if tunnel != null else {},
}
## The live pieces (placed and not being removed).
@@ -986,7 +988,15 @@ func underground_at(p: Vector3) -> bool:
## at `arrive` ("sea_cave", "tunnel_bottom"). Each worldlet keeps its own
## state file (Saves.state_path), so what you built here waits for you.
func travel(to: String, arrive: String) -> void:
if traveling or not Saves.has_world() or is_online() or server_mode:
if server_mode:
return # (on a server, the crossing is the player's game asking: player_net.gd "cross")
if is_online():
# The server checks, saves your character and sends you on (J3).
if not traveling and Time.get_ticks_msec() > _cross_asked + 3000:
_cross_asked = Time.get_ticks_msec()
PlayerNet.ask("cross", ["tunnel" if arrive == "sea_cave" else "sea_cave"])
return
if traveling or not Saves.has_world():
return
traveling = true
var id := Saves.current_id
@@ -1011,6 +1021,25 @@ func travel(to: String, arrive: String) -> void:
get_tree().change_scene_to_file.call_deferred(scene_file_path if not scene_file_path.is_empty() else "res://scenes/world.tscn")
signal travelled(to: String) ## saved and on the way to another worldlet
var _cross_asked := -100000 ## (online: when we last asked the server to cross)
## Online (J3): the server's sending us on to another land's server.
func _on_net_travelling(to: String) -> void:
traveling = true
player.set_physics_process(false)
if net_sync != null:
net_sync.set_process(false) # (nothing more to tell the land we're leaving,
net_sync.set_physics_process(false) # nor the next one about this one)
if hud != null:
hud.toast("On to the %s..." % Terrain.worldlet_name(to))
hud.fade(func(): pass)
## Online: in at the other land: the world reloads as that land (its terrain
## comes from what that server says, Net.world_info).
func _on_net_arrived(_to: String) -> void:
travelled.emit(_to)
if get_tree().current_scene == self:
get_tree().change_scene_to_file.call_deferred(scene_file_path if not scene_file_path.is_empty() else "res://scenes/world.tscn")
## Back in a land you've been to before: its clock comes forward to `to`
## ({day, time}, the clock where you've come from), and everything in it
@@ -1029,20 +1058,30 @@ func catch_up(to: Dictionary) -> float:
return secs
## Just arrived from another worldlet: put you where you came in.
## Where the way in called `at` puts you ("sea_cave", "tunnel_bottom"), or
## INF if this land has no such way in. (A server places crossing players
## here too: player_net.gd.)
func arrival_point(at: String) -> Vector3:
match at:
"sea_cave":
if sea_cave != null:
return sea_cave.front
"tunnel_bottom":
if tunnel != null and tunnel.dug >= tunnel.STRETCHES:
return tunnel.bottom + Vector3(0.8, 0.0, 0.0)
return Vector3.INF
func _arrive(at: String) -> void:
if at.is_empty():
return
var pos := Vector3.INF
var pos := arrival_point(at)
var facing := Vector3.FORWARD
match at:
"sea_cave":
if sea_cave != null:
pos = sea_cave.front
facing = (sea_cave.front - sea_cave.global_position).normalized()
"tunnel_bottom":
if tunnel != null and tunnel.dug >= tunnel.STRETCHES:
pos = tunnel.bottom + Vector3(0.8, 0.0, 0.0)
facing = Vector3(1, 0, 0)
facing = Vector3(1, 0, 0)
if pos == Vector3.INF:
push_warning("[world] nowhere to arrive at '%s': the start instead" % at)
_respawn()
@@ -1228,6 +1267,8 @@ func _go_online() -> void:
load_online_map() # (your map of this server, from your own computer)
Net.left.connect(func(_why = ""): save_online_map(), CONNECT_ONE_SHOT)
Net.left.connect(_on_net_left)
Net.travelling.connect(_on_net_travelling)
Net.arrived.connect(_on_net_arrived)
get_tree().auto_accept_quit = false # leave the server cleanly on window close
# The island's changes come from the server from now on.
props.regrow_enabled = false