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:
@@ -79,7 +79,15 @@ func server_join(peer: int, id: String, display: String) -> Vector3:
|
||||
p.load_data(d)
|
||||
var t: Node3D = WorldNet.world.terrain
|
||||
var pos := Vector3(d.pos[0], d.pos[1], d.pos[2]) if d.has("pos") else Vector3.INF
|
||||
if pos.is_finite() and t.inside_boundary(pos.x, pos.z, 1.0) and pos.y > t.sample_height(pos.x, pos.z) - 1.0:
|
||||
var here_ := String(d.get("land", Lands.here())) == Lands.here()
|
||||
if here_ and d.has("arrive"):
|
||||
# Just crossed over: where the way in comes out (J3).
|
||||
pos = WorldNet.world.arrival_point(String(d.arrive))
|
||||
elif not here_:
|
||||
pos = Vector3.INF # (saved somewhere else: start at this land's start)
|
||||
var ok_spot: bool = pos.is_finite() and (WorldNet.world.underground_at(pos) \
|
||||
or (t.inside_boundary(pos.x, pos.z, 1.0) and pos.y > t.sample_height(pos.x, pos.z) - 1.0))
|
||||
if ok_spot:
|
||||
at = pos
|
||||
print("[server] %s's character loaded" % display)
|
||||
if at != Vector3.INF:
|
||||
@@ -127,10 +135,54 @@ func _save(p: Node3D) -> void:
|
||||
if f == null:
|
||||
printerr("[server] can't save %s's character" % p.display)
|
||||
return
|
||||
f.store_string(JSON.stringify(p.to_data(), "\t"))
|
||||
var d: Dictionary = p.to_data()
|
||||
# Which land the character's in (J3: characters are shared by every land
|
||||
# of the world); heading somewhere, it's there they'll turn up next.
|
||||
d["land"] = String(p.get_meta("heading", Lands.here()))
|
||||
if p.has_meta("arrive"):
|
||||
d["arrive"] = String(p.get_meta("arrive"))
|
||||
f.store_string(JSON.stringify(d, "\t"))
|
||||
f.close()
|
||||
DirAccess.rename_absolute(tmp, path)
|
||||
|
||||
## Which land player `id`'s character is in ("" = not saved yet, or here).
|
||||
func land_of(id: String) -> String:
|
||||
return String(_read(_file(id)).get("land", ""))
|
||||
|
||||
## The hub: player `id` (at `peer`, not let in yet) left their character in
|
||||
## land `l`: start its server if need be and send them on there.
|
||||
func send_on(peer: int, id: String, l: String) -> void:
|
||||
print("[server] %s's character is in the %s: sending them on" % [id.substr(0, 8), l])
|
||||
Lands.ensure(l, func(why: String):
|
||||
if not why.is_empty():
|
||||
Net._reject(peer, "The %s isn't open right now (%s)" % [l, why])
|
||||
return
|
||||
Net.send_travel(peer, l, Lands.pass_to(l, id)))
|
||||
|
||||
## A crossing, on the server (the tunnel's sea cave, the cave back up): the
|
||||
## character is saved as heading for `to`, arriving at `arrive`, and their
|
||||
## game is sent on (to a land server, or back to the hub).
|
||||
func cross(peer: int, to: String, arrive: String) -> void:
|
||||
var p: Node3D = proxies.get(peer)
|
||||
if p == null or p.has_meta("heading"):
|
||||
return
|
||||
p.set_meta("heading", to)
|
||||
p.set_meta("arrive", arrive)
|
||||
_save(p)
|
||||
var id: String = p.player_id
|
||||
print("[server] %s crosses to the %s" % [p.display, to])
|
||||
if to == Lands.home() and not Lands.land.is_empty():
|
||||
Net.send_travel(peer, to, Lands.pass_home(id))
|
||||
return
|
||||
Lands.ensure(to, func(why: String):
|
||||
if not why.is_empty():
|
||||
p.remove_meta("heading")
|
||||
p.remove_meta("arrive")
|
||||
_save(p)
|
||||
tell(peer, "The way's blocked for now (%s)" % why)
|
||||
return
|
||||
Net.send_travel(peer, to, Lands.pass_to(to, id)))
|
||||
|
||||
static func _read(path: String) -> Dictionary:
|
||||
if not FileAccess.file_exists(path):
|
||||
return {}
|
||||
@@ -300,8 +352,42 @@ func _run(p: Node3D, what: String, a: Array) -> void:
|
||||
"hit":
|
||||
var n: Node3D = w.props.resource_nodes.get(_s(a, 0))
|
||||
var at: Vector3 = _v(a, 1)
|
||||
if n != null and is_instance_valid(n) and at.is_finite() and Actions.harvest_hit(p, n, at):
|
||||
if n == null and w.tunnel != null:
|
||||
var f: Node3D = w.tunnel.face_by_uid(_s(a, 0)) # (the cliff tunnel's seam or face)
|
||||
if f != null and at.is_finite():
|
||||
Actions.harvest_hit(p, f, at) # (the tunnel tells everyone: tunnel.gd)
|
||||
elif n != null and is_instance_valid(n) and at.is_finite() and Actions.harvest_hit(p, n, at):
|
||||
WorldNet.node_hit(n, at, p.global_position)
|
||||
"tunnel_prop":
|
||||
if w.tunnel != null:
|
||||
w.tunnel.set_prop(p, _i(a, 0))
|
||||
"tunnel_go":
|
||||
# Down into the cliff tunnel, or back out at the top: a teleport
|
||||
# the server makes (the tunnel's under the island), from nearby.
|
||||
var t: Node3D = w.tunnel
|
||||
if t == null or not t.opened:
|
||||
return
|
||||
var go_in := _s(a, 0) == "in"
|
||||
var from: Vector3 = t.seam_out if go_in else t.top
|
||||
if p.global_position.distance_to(from) > 4.5:
|
||||
return
|
||||
if go_in:
|
||||
t.go_in(p)
|
||||
else:
|
||||
t.go_out(p)
|
||||
Net.teleport(p.peer, p.global_position)
|
||||
_s2c_respawn.rpc_id(p.peer, p.global_position, p.rotation.y, "")
|
||||
"cross":
|
||||
# The sea cave's mouth (the Valley), or the sea cave (the Cove).
|
||||
var where := _s(a, 0)
|
||||
if where == "tunnel" and w.tunnel != null and w.tunnel.dug >= w.tunnel.STRETCHES \
|
||||
and p.global_position.distance_to(w.tunnel.cave_mouth) < 4.0:
|
||||
cross(p.peer, w.tunnel.to, "sea_cave")
|
||||
elif where == "sea_cave" and w.sea_cave != null and w.sea_cave.open() \
|
||||
and p.global_position.distance_to(w.sea_cave.front) < 6.0:
|
||||
cross(p.peer, w.sea_cave.to, "tunnel_bottom")
|
||||
elif where == "sea_cave" and w.sea_cave != null:
|
||||
tell(p.peer, w.sea_cave.interact_prompt(p))
|
||||
"pickup":
|
||||
var key := _s(a, 0)
|
||||
var pk: Node3D = WorldNet.find_pickup(key)
|
||||
@@ -456,6 +542,12 @@ func _run(p: Node3D, what: String, a: Array) -> void:
|
||||
w.day_night.apply(true)
|
||||
w.weather.snap()
|
||||
Net.push_clock()
|
||||
"debug_tunnel":
|
||||
# (tests) dig the cliff tunnel to `n` stretches, all propped.
|
||||
if cheats and w.tunnel != null:
|
||||
var n := clampi(_i(a, 0), 0, w.tunnel.STRETCHES)
|
||||
w.tunnel.load_data({"opened": true, "dug": n, "props": range(1, n + 1)})
|
||||
w.tunnel._tell_everyone()
|
||||
"debug_tp":
|
||||
var to := _v(a, 0)
|
||||
if cheats and to.is_finite():
|
||||
|
||||
Reference in New Issue
Block a user