M2.4: the server decides online (characters, inventory, stats, death, owned graves, per-player saves); death screen with Respawn after 3 s
This commit is contained in:
@@ -54,11 +54,23 @@ func _give(player: Node, id: String, n: int) -> int:
|
||||
return got
|
||||
|
||||
## Playing on a server: changes to the island go to it (world_net.gd), and
|
||||
## come back to everyone, us included. Our own inventory and stats stay here
|
||||
## until M2.4.
|
||||
## come back to everyone, us included.
|
||||
func _online() -> bool:
|
||||
return WorldNet.is_client()
|
||||
|
||||
## Online, the server decides (player_net.gd): every intent is sent there as
|
||||
## a request, and the server runs this same function on our character there.
|
||||
## Offline nothing changes: the game decides.
|
||||
func _ask(what: String, args: Array = []) -> bool:
|
||||
PlayerNet.ask(what, args)
|
||||
return true
|
||||
|
||||
const NOT_ONLINE := "Hunting and fishing aren't on servers yet (they come with the animals)"
|
||||
|
||||
func _not_online() -> bool:
|
||||
notify.emit(NOT_ONLINE)
|
||||
return false
|
||||
|
||||
func _in_reach(player: Node3D, target: Node3D, extra: float = 0.0) -> bool:
|
||||
return player.global_position.distance_to(target.global_position) <= REACH + 2.5 + extra
|
||||
|
||||
@@ -83,6 +95,8 @@ func can_craft(player: Node, recipe_id: String) -> bool:
|
||||
return inv.has_all(r.inputs) and station_near(player, r.station)
|
||||
|
||||
func craft(player: Node, recipe_id: String) -> bool:
|
||||
if _online():
|
||||
return _ask("craft", [recipe_id])
|
||||
var r: Dictionary = ItemDB.recipes.get(recipe_id, {})
|
||||
if r.is_empty():
|
||||
return false
|
||||
@@ -109,13 +123,9 @@ func craft(player: Node, recipe_id: String) -> bool:
|
||||
func pickup(player: Node3D, pickup_node: Node3D) -> bool:
|
||||
if not is_instance_valid(pickup_node) or not _in_reach(player, pickup_node):
|
||||
return false
|
||||
var id: String = pickup_node.item_id
|
||||
if _online():
|
||||
if player.inventory.space_for(id) < 1:
|
||||
notify.emit("Inventory full")
|
||||
return false
|
||||
WorldNet.take(pickup_node) # first come, first served: the server decides
|
||||
return true
|
||||
return _ask("pickup", [WorldNet.pickup_key(pickup_node)]) # first come, first served
|
||||
var id: String = pickup_node.item_id
|
||||
if _give(player, id, pickup_node.amount) <= 0:
|
||||
return false
|
||||
pickup_node.collected()
|
||||
@@ -125,6 +135,8 @@ func pickup(player: Node3D, pickup_node: Node3D) -> bool:
|
||||
func harvest_hit(player: Node3D, node: Node3D, hit_point: Vector3) -> bool:
|
||||
if not is_instance_valid(node) or node.depleted:
|
||||
return false
|
||||
if _online():
|
||||
return _ask("hit", [String(node.uid), hit_point])
|
||||
if player.global_position.distance_to(hit_point) > REACH + 1.0:
|
||||
return false
|
||||
var held: Dictionary = ItemDB.get_item(player.held_item_id())
|
||||
@@ -135,9 +147,6 @@ func harvest_hit(player: Node3D, node: Node3D, hit_point: Vector3) -> bool:
|
||||
if not player.survival.use_stamina(6.0):
|
||||
notify.emit("Too tired")
|
||||
return false
|
||||
if _online():
|
||||
WorldNet.hit(node, float(tool.get("damage", 1.0)), hit_point)
|
||||
return true
|
||||
var drops: Dictionary = node.hit(float(tool.get("damage", 1.0)), hit_point, player.global_position)
|
||||
for id in drops:
|
||||
_give(player, id, int(drops[id]))
|
||||
@@ -152,6 +161,8 @@ func can_place(player: Node3D, slot: int) -> bool:
|
||||
func place(player: Node3D, slot: int, xf: Transform3D, world: Node3D) -> bool:
|
||||
if not can_place(player, slot):
|
||||
return false
|
||||
if _online():
|
||||
return _ask("place", [slot, xf])
|
||||
if player.global_position.distance_to(xf.origin) > 8.0:
|
||||
return false
|
||||
var id: String = player.inventory.get_slot(slot).id
|
||||
@@ -160,9 +171,6 @@ func place(player: Node3D, slot: int, xf: Transform3D, world: Node3D) -> bool:
|
||||
notify.emit("Can't place that here")
|
||||
return false
|
||||
player.inventory.take_from(slot, 1)
|
||||
if _online():
|
||||
WorldNet.place(id, xf) # (given back if the server says no)
|
||||
return true
|
||||
world.spawn_piece(def, xf)
|
||||
return true
|
||||
|
||||
@@ -171,6 +179,8 @@ func place(player: Node3D, slot: int, xf: Transform3D, world: Node3D) -> bool:
|
||||
func dismantle(player: Node3D, piece: Node3D) -> bool:
|
||||
if not is_instance_valid(piece) or not piece.is_in_group("piece") or piece.is_queued_for_deletion():
|
||||
return false
|
||||
if _online():
|
||||
return _ask("dismantle", [WorldNet.nid(piece)])
|
||||
if player.global_position.distance_to(piece.global_position) > 8.0:
|
||||
return false
|
||||
if piece.item_id == "grave":
|
||||
@@ -183,9 +193,6 @@ func dismantle(player: Node3D, piece: Node3D) -> bool:
|
||||
if player.inventory.space_for(piece.item_id) < 1:
|
||||
notify.emit("Inventory full")
|
||||
return false
|
||||
if _online():
|
||||
WorldNet.dismantle(piece)
|
||||
return true
|
||||
_give(player, piece.item_id, 1)
|
||||
piece.get_parent().get_parent().remove_piece(piece, player)
|
||||
return true
|
||||
@@ -194,8 +201,7 @@ func toggle_door(player: Node3D, door: Node3D) -> bool:
|
||||
if not is_instance_valid(door) or not _in_reach(player, door, 1.0):
|
||||
return false
|
||||
if _online():
|
||||
WorldNet.door(door)
|
||||
return true
|
||||
return _ask("door", [WorldNet.nid(door)])
|
||||
door.set_open(not door.open)
|
||||
return true
|
||||
|
||||
@@ -203,9 +209,16 @@ func toggle_door(player: Node3D, door: Node3D) -> bool:
|
||||
func use_bed(player: Node3D, bed: Node3D) -> bool:
|
||||
if not is_instance_valid(bed) or not _in_reach(player, bed, 1.0):
|
||||
return false
|
||||
if _online():
|
||||
return _ask("bed", [WorldNet.nid(bed)])
|
||||
var world: Node = bed.get_parent().get_parent()
|
||||
if not bed.is_spawn():
|
||||
world.set_bed_spawn(bed)
|
||||
# On a server each player has their own bed (server_player.gd).
|
||||
var mine: bool = player.claims_bed(bed) if player.has_method("claims_bed") else bed.is_spawn()
|
||||
if not mine:
|
||||
if player.has_method("claim_bed"):
|
||||
player.claim_bed(bed)
|
||||
else:
|
||||
world.set_bed_spawn(bed)
|
||||
notify.emit("Spawn point set")
|
||||
return true
|
||||
var why: String = world.sleep_block_reason(bed)
|
||||
@@ -237,6 +250,8 @@ func melee_stats(player: Node) -> Dictionary:
|
||||
|
||||
## One melee blow at an animal.
|
||||
func melee(player: Node3D, target: Node3D) -> bool:
|
||||
if _online():
|
||||
return _not_online()
|
||||
if not is_instance_valid(target) or not target.is_in_group("creature"):
|
||||
return false
|
||||
var m := melee_stats(player)
|
||||
@@ -264,6 +279,8 @@ func projectile_hit(shooter: Node3D, target: Node3D, damage: float, at: Vector3,
|
||||
|
||||
## Throws the spear in `slot` from `origin` along `dir`.
|
||||
func throw_spear(player: Node3D, slot: int, origin: Vector3, dir: Vector3, world: Node3D) -> bool:
|
||||
if _online():
|
||||
return _not_online()
|
||||
var s = player.inventory.get_slot(slot)
|
||||
if s == null:
|
||||
return false
|
||||
@@ -281,6 +298,8 @@ func throw_spear(player: Node3D, slot: int, origin: Vector3, dir: Vector3, world
|
||||
|
||||
## Starts drawing the held bow: needs arrows and a little stamina.
|
||||
func can_draw(player: Node3D) -> bool:
|
||||
if _online():
|
||||
return _not_online()
|
||||
var bow: Dictionary = ItemDB.get_item(player.held_item_id()).get("bow", {})
|
||||
if bow.is_empty():
|
||||
return false
|
||||
@@ -294,6 +313,8 @@ func can_draw(player: Node3D) -> bool:
|
||||
|
||||
## Looses an arrow. `power` 0..1 is how far the bow was drawn.
|
||||
func shoot(player: Node3D, origin: Vector3, dir: Vector3, power: float, world: Node3D) -> bool:
|
||||
if _online():
|
||||
return _not_online()
|
||||
var bow: Dictionary = ItemDB.get_item(player.held_item_id()).get("bow", {})
|
||||
if bow.is_empty() or player.global_position.distance_to(origin) > 2.5:
|
||||
return false
|
||||
@@ -306,6 +327,8 @@ func shoot(player: Node3D, origin: Vector3, dir: Vector3, power: float, world: N
|
||||
return true
|
||||
|
||||
func butcher(player: Node3D, carcass: Node3D) -> bool:
|
||||
if _online():
|
||||
return _not_online()
|
||||
if not is_instance_valid(carcass) or not carcass.is_in_group("carcass") or not _in_reach(player, carcass, 1.0):
|
||||
return false
|
||||
var drops: Dictionary = carcass.butcher_drops()
|
||||
@@ -322,6 +345,8 @@ func butcher(player: Node3D, carcass: Node3D) -> bool:
|
||||
|
||||
## Casts the held rod from `origin` along `dir`.
|
||||
func cast_line(player: Node3D, origin: Vector3, dir: Vector3, world: Node3D) -> bool:
|
||||
if _online():
|
||||
return _not_online()
|
||||
var rod: Dictionary = ItemDB.get_item(player.held_item_id()).get("fishing", {})
|
||||
if rod.is_empty() or player.global_position.distance_to(origin) > 2.5:
|
||||
return false
|
||||
@@ -335,6 +360,8 @@ func cast_line(player: Node3D, origin: Vector3, dir: Vector3, world: Node3D) ->
|
||||
|
||||
## Reels in. With a fish biting you land it; otherwise the line just comes in.
|
||||
func reel(player: Node3D, world: Node3D) -> bool:
|
||||
if _online():
|
||||
return _not_online()
|
||||
var b: Node3D = world.bobber
|
||||
if b == null or not is_instance_valid(b):
|
||||
return false
|
||||
@@ -351,6 +378,8 @@ func reel(player: Node3D, world: Node3D) -> bool:
|
||||
|
||||
## Puts on the cloak in `slot` (swapping out any cloak you were wearing).
|
||||
func wear(player: Node3D, slot: int) -> bool:
|
||||
if _online():
|
||||
return _ask("wear", [slot])
|
||||
var s = player.inventory.get_slot(slot)
|
||||
if s == null or not ItemDB.get_item(s.id).has("wear"):
|
||||
return false
|
||||
@@ -366,6 +395,8 @@ func wear(player: Node3D, slot: int) -> bool:
|
||||
func take_off(player: Node3D) -> bool:
|
||||
if player.worn.is_empty():
|
||||
return false
|
||||
if _online():
|
||||
return _ask("take_off")
|
||||
if player.inventory.space_for(player.worn) < 1:
|
||||
notify.emit("Inventory full")
|
||||
return false
|
||||
@@ -378,8 +409,7 @@ func forage(player: Node3D, bush: Node3D) -> bool:
|
||||
if not is_instance_valid(bush) or not _in_reach(player, bush) or not bush.ripe():
|
||||
return false
|
||||
if _online():
|
||||
WorldNet.forage(bush)
|
||||
return true
|
||||
return _ask("forage", [String(bush.uid)])
|
||||
var got: Dictionary = bush.harvest()
|
||||
for id in got:
|
||||
_give(player, id, int(got[id]))
|
||||
@@ -387,6 +417,8 @@ func forage(player: Node3D, bush: Node3D) -> bool:
|
||||
|
||||
## Eats one of the food in `slot`.
|
||||
func eat(player: Node3D, slot: int) -> bool:
|
||||
if _online():
|
||||
return _ask("eat", [slot])
|
||||
var s = player.inventory.get_slot(slot)
|
||||
if s == null:
|
||||
return false
|
||||
@@ -406,16 +438,15 @@ func eat(player: Node3D, slot: int) -> bool:
|
||||
func add_fuel(player: Node3D, fire: Node3D) -> bool:
|
||||
if not is_instance_valid(fire) or not _in_reach(player, fire):
|
||||
return false
|
||||
if _online():
|
||||
return _ask("fuel", [WorldNet.nid(fire)])
|
||||
if fire.fuel >= fire.MAX_FUEL - 1.0:
|
||||
notify.emit("The fire is fully stoked")
|
||||
return false
|
||||
for id in ["wood", "stick", "fiber"]:
|
||||
if player.inventory.count(id) > 0:
|
||||
player.inventory.remove(id, 1)
|
||||
if _online():
|
||||
WorldNet.fuel(fire, id)
|
||||
else:
|
||||
fire.add_fuel(float(ItemDB.get_item(id).get("fuel", 10)))
|
||||
fire.add_fuel(float(ItemDB.get_item(id).get("fuel", 10)))
|
||||
notify.emit("Added %s to the fire" % ItemDB.item_name(id).to_lower())
|
||||
return true
|
||||
notify.emit("Nothing to burn (wood or sticks)")
|
||||
@@ -426,14 +457,8 @@ func add_fuel(player: Node3D, fire: Node3D) -> bool:
|
||||
func transfer(player: Node3D, from: Inventory, slot: int, to: Inventory, container: Node3D = null) -> void:
|
||||
if container != null and not _in_reach(player, container, 1.0):
|
||||
return
|
||||
if _online() and container != null:
|
||||
var s = from.get_slot(slot)
|
||||
if s == null:
|
||||
return
|
||||
if from == player.inventory:
|
||||
from.set_slot(slot, null)
|
||||
WorldNet.chest_put(container, s) # what doesn't fit comes back
|
||||
else:
|
||||
WorldNet.chest_take(container, slot, to.space_for(s.id))
|
||||
if _online():
|
||||
if container != null:
|
||||
_ask("transfer", [WorldNet.nid(container), slot, from == player.inventory])
|
||||
return
|
||||
from.quick_move(slot, to)
|
||||
|
||||
Reference in New Issue
Block a user