The high-level multiplayer API in Godot appears to introduce ways for players to cheat too easily. As a precaution, players can now hopefully only send messages to the server, which relays them to each player, after potentially validating them. - Player's Name is set to their network ID, DisplayName accessible through new property - Add Authenticating NetworkStatus: This is where new players will send data about themselves, currently appearance. - Use _Ready instead of _EnterTree where applicable - Add Init extension method: Allows initializing members before the node has been added to the scene tree. - Add Rpc/RsetExcept extension methodsmain
parent
44298a707b
commit
d93baa7fd0
14 changed files with 321 additions and 222 deletions
@ -1,21 +0,0 @@ |
|||||||
using Godot; |
|
||||||
|
|
||||||
public class Camera : Camera2D |
|
||||||
{ |
|
||||||
public Cursor Cursor { get; private set; } |
|
||||||
|
|
||||||
public override void _EnterTree() |
|
||||||
{ |
|
||||||
// Cursor = GetViewport().GetNode<Cursor>("Cursor"); |
|
||||||
} |
|
||||||
|
|
||||||
public override void _Process(float delta) |
|
||||||
{ |
|
||||||
// TODO: Implement some kind of "zoom" mechanic? |
|
||||||
// var mousePos = GetTree().Root.GetMousePosition(); |
|
||||||
// var centerPos = OS.WindowSize / 2; |
|
||||||
// var scale = ((Viewport)GetViewport()).Scale; |
|
||||||
// Position = !Cursor.Visible ? Vector2.Zero |
|
||||||
// : ((mousePos - centerPos) / scale).Clamped(MaxDistance) / 2; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,42 @@ |
|||||||
|
using Godot; |
||||||
|
using System; |
||||||
|
|
||||||
|
public class LocalPlayer : Player |
||||||
|
{ |
||||||
|
public TimeSpan JumpEarlyTime { get; } = TimeSpan.FromSeconds(0.2F); |
||||||
|
public TimeSpan JumpCoyoteTime { get; } = TimeSpan.FromSeconds(0.2F); |
||||||
|
|
||||||
|
[Export] public float Speed { get; set; } = 120; |
||||||
|
[Export] public float JumpSpeed { get; set; } = 180; |
||||||
|
[Export] public float Gravity { get; set; } = 400; |
||||||
|
|
||||||
|
[Export(PropertyHint.Range, "0,1")] |
||||||
|
public float Friction { get; set; } = 0.1F; |
||||||
|
[Export(PropertyHint.Range, "0,1")] |
||||||
|
public float Acceleration { get; set; } = 0.25F; |
||||||
|
|
||||||
|
private Vector2 _velocity = Vector2.Zero; |
||||||
|
private DateTime? _jumpPressed = null; |
||||||
|
private DateTime? _lastOnFloor = null; |
||||||
|
|
||||||
|
public override void _PhysicsProcess(float delta) |
||||||
|
{ |
||||||
|
var moveDir = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"); |
||||||
|
_velocity.x = (moveDir != 0) ? Mathf.Lerp(_velocity.x, moveDir * Speed, Acceleration) |
||||||
|
: Mathf.Lerp(_velocity.x, 0, Friction); |
||||||
|
_velocity.y += Gravity * delta; |
||||||
|
_velocity = MoveAndSlide(_velocity, Vector2.Up); |
||||||
|
|
||||||
|
if (Input.IsActionJustPressed("move_jump")) |
||||||
|
_jumpPressed = DateTime.Now; |
||||||
|
if (IsOnFloor()) |
||||||
|
_lastOnFloor = DateTime.Now; |
||||||
|
|
||||||
|
if (((DateTime.Now - _jumpPressed) <= JumpEarlyTime) && |
||||||
|
((DateTime.Now - _lastOnFloor) <= JumpCoyoteTime)) { |
||||||
|
_velocity.y = -JumpSpeed; |
||||||
|
_jumpPressed = null; |
||||||
|
_lastOnFloor = null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,42 +1,93 @@ |
|||||||
using Godot; |
using Godot; |
||||||
using System; |
|
||||||
|
|
||||||
public class Player : KinematicBody2D |
// FIXME: Player name should not be stored in "Name". |
||||||
|
public class Player : KinematicBody2D, IInitializer |
||||||
{ |
{ |
||||||
public TimeSpan JumpEarlyTime { get; } = TimeSpan.FromSeconds(0.2F); |
[Export] public NodePath DisplayNamePath { get; set; } |
||||||
public TimeSpan JumpCoyoteTime { get; } = TimeSpan.FromSeconds(0.2F); |
[Export] public NodePath SpritePath { get; set; } |
||||||
|
|
||||||
[Export] public float Speed { get; set; } = 120; |
public Label DisplayNameLabel { get; private set; } |
||||||
[Export] public float JumpSpeed { get; set; } = 180; |
public Sprite Sprite { get; private set; } |
||||||
[Export] public float Gravity { get; set; } = 400; |
public Network Network { get; private set; } |
||||||
|
|
||||||
[Export(PropertyHint.Range, "0,1")] |
public bool IsLocal => this is LocalPlayer; |
||||||
public float Friction { get; set; } = 0.1F; |
|
||||||
[Export(PropertyHint.Range, "0,1")] |
private int _networkId = -1; |
||||||
public float Acceleration { get; set; } = 0.25F; |
public int NetworkId { |
||||||
|
get => _networkId; |
||||||
|
set => SetNetworkId(value); |
||||||
|
} |
||||||
|
|
||||||
|
public Color Color { |
||||||
|
get => Sprite.Modulate; |
||||||
|
set => SetColor(value); |
||||||
|
} |
||||||
|
|
||||||
|
public string DisplayName { |
||||||
|
get => DisplayNameLabel.Text; |
||||||
|
set => SetDisplayName(value); |
||||||
|
} |
||||||
|
|
||||||
private Vector2 _velocity = Vector2.Zero; |
|
||||||
private DateTime? _jumpPressed = null; |
|
||||||
private DateTime? _lastOnFloor = null; |
|
||||||
|
|
||||||
public override void _PhysicsProcess(float delta) |
public void Initialize() |
||||||
{ |
{ |
||||||
var moveDir = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"); |
DisplayNameLabel = GetNode<Label>(DisplayNamePath); |
||||||
_velocity.x = (moveDir != 0) ? Mathf.Lerp(_velocity.x, moveDir * Speed, Acceleration) |
Sprite = GetNode<Sprite>(SpritePath); |
||||||
: Mathf.Lerp(_velocity.x, 0, Friction); |
} |
||||||
_velocity.y += Gravity * delta; |
|
||||||
_velocity = MoveAndSlide(_velocity, Vector2.Up); |
public override void _Ready() |
||||||
|
{ |
||||||
|
Initialize(); |
||||||
|
Network = GetNode<Network>("/root/Game/Network"); |
||||||
|
|
||||||
if (Input.IsActionJustPressed("move_jump")) |
RsetConfig("position", MultiplayerAPI.RPCMode.Puppetsync); |
||||||
_jumpPressed = DateTime.Now; |
Sprite.RsetConfig("modulate", MultiplayerAPI.RPCMode.Puppetsync); |
||||||
if (IsOnFloor()) |
DisplayNameLabel.RsetConfig("text", MultiplayerAPI.RPCMode.Puppetsync); |
||||||
_lastOnFloor = DateTime.Now; |
} |
||||||
|
|
||||||
if (((DateTime.Now - _jumpPressed) <= JumpEarlyTime) && |
public override void _Process(float delta) |
||||||
((DateTime.Now - _lastOnFloor) <= JumpCoyoteTime)) { |
{ |
||||||
_velocity.y = -JumpSpeed; |
if (GetTree().NetworkPeer != null) { |
||||||
_jumpPressed = null; |
// TODO: Only send position if it changed. |
||||||
_lastOnFloor = null; |
// Send unreliable messages while moving, and a reliable once the player stopped. |
||||||
|
if (GetTree().IsNetworkServer()) |
||||||
|
this.RsetUnreliableExcept(NetworkId, "position", Position); |
||||||
|
else if (Network.Status == NetworkStatus.ConnectedToServer) |
||||||
|
RpcUnreliable(nameof(OnPositionChanged), Position); |
||||||
|
} |
||||||
|
} |
||||||
|
[Master] |
||||||
|
private void OnPositionChanged(Vector2 value) |
||||||
|
{ if (GetTree().GetRpcSenderId() == NetworkId) Position = value; } |
||||||
|
|
||||||
|
|
||||||
|
private void SetNetworkId(int value) |
||||||
|
{ |
||||||
|
_networkId = value; |
||||||
|
Name = (_networkId > 0) ? value.ToString() : "LocalPlayer"; |
||||||
|
} |
||||||
|
|
||||||
|
private void SetColor(Color value) |
||||||
|
{ |
||||||
|
Sprite.Modulate = value; |
||||||
|
if (IsInsideTree() && GetTree().NetworkPeer != null) { |
||||||
|
if (GetTree().IsNetworkServer()) Sprite.RsetExcept(NetworkId, "modulate", value); |
||||||
|
else Rpc(nameof(OnColorChanged), value); |
||||||
|
} |
||||||
|
} |
||||||
|
[Master] |
||||||
|
private void OnColorChanged(Color value) |
||||||
|
{ if (GetTree().GetRpcSenderId() == NetworkId) Color = value; } |
||||||
|
|
||||||
|
private void SetDisplayName(string value) |
||||||
|
{ |
||||||
|
DisplayNameLabel.Text = value; |
||||||
|
if (IsInsideTree() && GetTree().NetworkPeer != null) { |
||||||
|
if (GetTree().IsNetworkServer()) DisplayNameLabel.RsetExcept(NetworkId, "text", value); |
||||||
|
else Rpc(nameof(OnDisplayNameChanged), value); |
||||||
} |
} |
||||||
} |
} |
||||||
|
[Master] |
||||||
|
private void OnDisplayNameChanged(string value) |
||||||
|
{ if (GetTree().GetRpcSenderId() == NetworkId) DisplayName = value; } |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue