Remove LocalPlayer ... again

- Add PlayerMovement, child node
  of Player which handles movement
- PlayerMovement and Camera are
  added through code when spawned
- Add Player.IsLocal property
- Move Velocity property to Player
- Remove ResetPosition, instead just
  use RsetId on Position and Velocity
main
copygirl 4 years ago
parent 7c4ae2ce45
commit 3352518f08
  1. 11
      scene/LocalPlayer.tscn
  2. 3
      src/EscapeMenuWorld.cs
  3. 7
      src/Items/CreativeBuilding.cs
  4. 18
      src/Items/Weapon.cs
  5. 8
      src/Objects/Player.cs
  6. 37
      src/Objects/PlayerMovement.cs
  7. 14
      src/Scenes/Client.cs
  8. 10
      src/World.cs

@ -1,11 +0,0 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://scene/Player.tscn" type="PackedScene" id=1]
[ext_resource path="res://src/Objects/LocalPlayer.cs" type="Script" id=2]
[node name="LocalPlayer" instance=ExtResource( 1 )]
script = ExtResource( 2 )
[node name="Camera" type="Camera2D" parent="." index="0"]
pause_mode = 2
current = true

@ -106,7 +106,8 @@ public class EscapeMenuWorld : CenterContainer
foreach (var player in server.GetWorld().Players) {
// Reset players' positions.
// Can't use RPC helper method here since player is not a LocalPlayer here.
player.RpcId(player.NetworkID, nameof(LocalPlayer.ResetPosition), Vector2.Zero);
player.RsetId(player.NetworkID, "position", Vector2.Zero);
player.RsetId(player.NetworkID, nameof(Player.Velocity), Vector2.Zero);
// Reset the visbility tracker so the client will receive new chunks.
player.VisibilityTracker.Reset();
}

@ -35,7 +35,7 @@ public class CreativeBuilding : Node2D
public override void _UnhandledInput(InputEvent ev)
{
if (!Visible || !(Player is LocalPlayer) || !Player.IsAlive) return;
if (!Visible || !Player.IsLocal || !Player.IsAlive) return;
if (ev.IsActionPressed("interact_primary")) {
GetTree().SetInputAsHandled();
@ -49,7 +49,7 @@ public class CreativeBuilding : Node2D
public override void _Process(float delta)
{
if (!(Player is LocalPlayer)) return;
if (!Player.IsLocal) return;
if (!Visible || !Player.IsAlive) _currentMode = null;
if (_currentMode == BuildMode.Placing) {
@ -86,8 +86,7 @@ public class CreativeBuilding : Node2D
public override void _Draw()
{
if (!(Player is LocalPlayer) || !Cursor.Visible ||
EscapeMenu.Instance.Visible) return;
if (!Player.IsLocal || !Cursor.Visible || EscapeMenu.Instance.Visible) return;
var green = Color.FromHsv(1.0F / 3, 1.0F, 1.0F, 0.4F);
var red = Color.FromHsv(0.0F, 1.0F, 1.0F, 0.4F);

@ -60,7 +60,7 @@ public class Weapon : Sprite
public override void _UnhandledInput(InputEvent ev)
{
if (!(Player is LocalPlayer)) return;
if (!Player.IsLocal) return;
if (ev.IsActionPressed("interact_primary"))
{ HoldingTrigger = TimeSpan.Zero; OnTriggerPressed(); }
if (ev.IsActionPressed("interact_reload")) Reload();
@ -82,7 +82,7 @@ public class Weapon : Sprite
_reloadDelay = 0.0F;
Rounds = Capacity;
HoldingTrigger = null;
if (Player is LocalPlayer) Update();
if (Player.IsLocal) Update();
} else if (Visible) {
if (HoldingTrigger is TimeSpan holding)
HoldingTrigger = holding + TimeSpan.FromSeconds(delta);
@ -101,7 +101,7 @@ public class Weapon : Sprite
_fireDelay = 0;
}
if (Player is LocalPlayer) {
if (Player.IsLocal) {
// Automatically reload when out of rounds.
if (Rounds <= 0) Reload();
@ -165,7 +165,7 @@ public class Weapon : Sprite
if (float.IsNaN(value = Mathf.PosMod(value, Mathf.Tau))) return;
RPC.Unreliable(SendAimAngle, value);
} else if (!(Player is LocalPlayer))
} else if (!Player.IsLocal)
AimDirection = value;
}
@ -175,7 +175,7 @@ public class Weapon : Sprite
var seed = unchecked((int)GD.Randi());
if (!FireInternal(AimDirection, Scale.y > 0, seed)) return;
RPC.Reliable(1, SendFire, AimDirection, Scale.y > 0, seed);
((LocalPlayer)Player).Velocity -= Mathf.Polar2Cartesian(Knockback, Rotation);
Player.Velocity -= Mathf.Polar2Cartesian(Knockback, Rotation);
}
protected virtual bool FireInternal(float aimDirection, bool toRight, int seed)
@ -209,7 +209,7 @@ public class Weapon : Sprite
_currentSpreadInc += Mathf.Deg2Rad(SpreadIncrease);
_currentRecoil += Mathf.Deg2Rad(random.NextFloat(RecoilMin, RecoilMax));
if (isServer || (Player is LocalPlayer)) {
if (isServer || Player.IsLocal) {
// Do not keep track of fire rate or ammo for other players.
_fireDelay += 60.0F / RateOfFire;
Rounds -= 1;
@ -227,7 +227,7 @@ public class Weapon : Sprite
// TODO: Only send to players who can see the full path of the bullet.
if (FireInternal(aimDirection, toRight, seed))
RPC.Reliable(SendFire, aimDirection, toRight, seed);
} else if (!(Player is LocalPlayer))
} else if (!Player.IsLocal)
FireInternal(aimDirection, toRight, seed);
}
@ -250,14 +250,14 @@ public class Weapon : Sprite
if (this.GetGame() is Server) {
if (Player.NetworkID != GetTree().GetRpcSenderId()) return;
if (ReloadInternal()) RPC.Reliable(SendReload);
} else if (!(Player is LocalPlayer))
} else if (!Player.IsLocal)
ReloadInternal();
}
public override void _Draw()
{
if (!(Player is LocalPlayer) || !Player.IsAlive || _lowered) return;
if (!Player.IsLocal || !Player.IsAlive || _lowered) return;
// Draws an "aiming cone" to show where bullets might travel.
var tip = TipOffset + new Vector2(4, 0);

@ -16,9 +16,12 @@ public class Player : KinematicBody2D, IInitializable
public IItems Items { get; private set; }
public int NetworkID { get => int.Parse(Name); set => Name = value.ToString(); }
public bool IsLocal => NetworkID == GetTree().GetNetworkUniqueId();
public string DisplayName { get => DisplayNameLabel.Text; set => DisplayNameLabel.Text = value; }
public Color Color { get => Sprite.SelfModulate; set => Sprite.SelfModulate = value; }
public Vector2 Velocity { get; set; }
public float Health { get; set; } = 1.0F;
public bool IsAlive => Health > 0.0F;
private float _previousHealth;
@ -37,6 +40,7 @@ public class Player : KinematicBody2D, IInitializable
RsetConfig("modulate", MultiplayerAPI.RPCMode.Puppetsync);
RsetConfig(nameof(DisplayName), MultiplayerAPI.RPCMode.Puppetsync);
RsetConfig(nameof(Color), MultiplayerAPI.RPCMode.Puppetsync);
RsetConfig(nameof(Velocity), MultiplayerAPI.RPCMode.Puppet);
RsetConfig(nameof(Health), MultiplayerAPI.RPCMode.Puppet);
}
@ -59,8 +63,8 @@ public class Player : KinematicBody2D, IInitializable
if (!IsAlive && ((_respawnDelay += delta) > RESPAWN_TIMER.TotalSeconds)) {
// TODO: Move respawning related code to its own method.
// Can't use RPC helper method here since player is not a LocalPlayer here.
RpcId(NetworkID, nameof(LocalPlayer.ResetPosition), Vector2.Zero);
RsetId(NetworkID, "position", Vector2.Zero);
RsetId(NetworkID, nameof(Velocity), Vector2.Zero);
Rset("modulate", Colors.White);
Health = 1.0F;
_respawnDelay = 0.0F;

@ -1,7 +1,7 @@
using System;
using Godot;
public class LocalPlayer : Player
public class PlayerMovement : Node
{
// TODO: Implement "low jumps" activated by releasing the jump button early.
public TimeSpan JumpEarlyTime { get; } = TimeSpan.FromSeconds(0.2F);
@ -15,47 +15,40 @@ public class LocalPlayer : Player
public float GroundFriction { get; set; } = 0.2F;
public float AirFriction { get; set; } = 0.05F;
public Vector2 Velocity = Vector2.Zero;
private Player _player;
private DateTime? _jumpPressed = null;
private DateTime? _lastOnFloor = null;
public override void _Ready()
=> _player = GetParent<Player>();
public override void _Process(float delta)
{
base._Process(delta);
RPC.Unreliable(1, Move, Position);
}
=> RPC.Unreliable(1, _player.Move, _player.Position);
public override void _PhysicsProcess(float delta)
{
var moveDir = 0.0F;
var jumpPressed = false;
if (!EscapeMenu.Instance.Visible && IsAlive) {
if (!EscapeMenu.Instance.Visible && _player.IsAlive) {
moveDir = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left");
jumpPressed = Input.IsActionJustPressed("move_jump");
}
var friction = IsOnFloor() ? GroundFriction : AirFriction;
Velocity.x = (moveDir != 0) ? Mathf.Lerp(Velocity.x, moveDir * MovementSpeed, Acceleration)
: Mathf.Lerp(Velocity.x, 0, friction);
Velocity.y += Gravity * delta;
Velocity = MoveAndSlide(Velocity, Vector2.Up);
var velocity = _player.Velocity;
var friction = _player.IsOnFloor() ? GroundFriction : AirFriction;
velocity.x = (moveDir != 0) ? Mathf.Lerp(_player.Velocity.x, moveDir * MovementSpeed, Acceleration)
: Mathf.Lerp(_player.Velocity.x, 0, friction);
velocity.y += Gravity * delta;
_player.Velocity = _player.MoveAndSlide(velocity, Vector2.Up);
if (jumpPressed) _jumpPressed = DateTime.Now;
if (IsOnFloor()) _lastOnFloor = DateTime.Now;
if (_player.IsOnFloor()) _lastOnFloor = DateTime.Now;
if (((DateTime.Now - _jumpPressed) <= JumpEarlyTime) &&
((DateTime.Now - _lastOnFloor) <= JumpCoyoteTime)) {
Velocity.y = -JumpVelocity;
_player.Velocity -= new Vector2(0, JumpVelocity);
_jumpPressed = null;
_lastOnFloor = null;
}
}
[Puppet]
public void ResetPosition(Vector2 position)
{
Position = position;
Velocity = Vector2.Zero;
}
}

@ -12,15 +12,15 @@ public class Client : Game
public NetworkedMultiplayerENet Peer => (NetworkedMultiplayerENet)Multiplayer.NetworkPeer;
public ConnectionStatus Status => Peer?.GetConnectionStatus() ?? ConnectionStatus.Disconnected;
public LocalPlayer LocalPlayer => (LocalPlayer)this.GetWorld().GetPlayer(GetTree().GetNetworkUniqueId());
private LocalPlayer _storedLocalPlayer;
public Player LocalPlayer => this.GetWorld().GetPlayer(GetTree().GetNetworkUniqueId());
private Player _storedLocalPlayer;
public event Action Connected;
public event Action Disconnected;
public event Action<LocalPlayer> LocalPlayerSpawned;
public event Action<Player> LocalPlayerSpawned;
public event Action<ConnectionStatus> StatusChanged;
internal void FireLocalPlayerSpawned(LocalPlayer player)
internal void FireLocalPlayerSpawned(Player player)
=> LocalPlayerSpawned?.Invoke(player);
@ -57,9 +57,9 @@ public class Client : Game
if (IntegratedServer.Server.IsRunning) {
foreach (var player in this.GetWorld().Players) {
// Store the local player for later restoration, but remove it from the scene.
if (player is LocalPlayer localPlayer) {
_storedLocalPlayer = localPlayer;
localPlayer.GetParent().RemoveChild(localPlayer);
if (player.IsLocal) {
_storedLocalPlayer = player;
player.GetParent().RemoveChild(player);
// Do NOT call QueueFree - like RemoveFromParent does.
} else player.RemoveFromParent();
}

@ -61,14 +61,16 @@ public class World : Node
[PuppetSync]
public void SpawnPlayer(int networkID, Vector2 position)
{
var isLocal = networkID == GetTree().GetNetworkUniqueId();
var player = (isLocal ? LOCAL_PLAYER : PLAYER).Init<Player>();
var player = SceneCache<Player>.Instance();
player.NetworkID = networkID;
player.Position = position;
PlayerContainer.AddChild(player);
if (player is LocalPlayer localPlayer)
this.GetClient().FireLocalPlayerSpawned(localPlayer);
if (player.IsLocal) {
player.AddChild(new PlayerMovement { Name = "PlayerMovement" });
player.AddChild(new Camera2D { Name = "Camera", Current = true });
this.GetClient().FireLocalPlayerSpawned(player);
}
if (this.GetGame() is Server) {
player.VisibilityTracker.ChunkTracked += (chunkPos) => {

Loading…
Cancel
Save