Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement player abilities packet #433

Merged
merged 2 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Obsidian.API/_Interfaces/IPlayer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net;
using Obsidian.API._Types;
using System.Net;

namespace Obsidian.API;

Expand All @@ -21,6 +22,8 @@ public interface IPlayer : ILiving
public IPAddress? ClientIP { get; }
public Gamemode Gamemode { get; set; }

public PlayerAbility Abilities { get; }

public bool Sleeping { get; set; }
public bool InHorseInventory { get; set; }

Expand Down
11 changes: 11 additions & 0 deletions Obsidian.API/_Types/PlayerAbility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Obsidian.API;

[Flags]
public enum PlayerAbility
{
None = 0x00,
Invulnerable = 0x01,
Flying = 0x02,
AllowFlying = 0x04,
CreativeMode = 0x08
}
4 changes: 4 additions & 0 deletions Obsidian/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,10 @@ internal async Task SendPlayerInfoAsync()
}

await QueuePacketAsync(new PlayerInfoUpdatePacket(dict));
await QueuePacketAsync(new PlayerAbilitiesPacket(true)
{
Abilities = Player.Abilities
});
}

internal void SendPacket(IClientboundPacket packet)
Expand Down
22 changes: 21 additions & 1 deletion Obsidian/Entities/Player.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This would be saved in a file called [playeruuid].dat which holds a bunch of NBT data.
// https://wiki.vg/Map_Format
using Microsoft.Extensions.Logging;
using Obsidian.API._Types;
using Obsidian.API.Events;
using Obsidian.API.Utilities;
using Obsidian.Nbt;
Expand Down Expand Up @@ -62,7 +63,24 @@ public sealed partial class Player : Living, IPlayer

public IBlock? LastClickedBlock { get; internal set; }

public Gamemode Gamemode { get; set; }
public Gamemode Gamemode
{
get => gamemode;
set
{
gamemode = value;

Abilities = Gamemode switch
{
Gamemode.Creative => PlayerAbility.CreativeMode | PlayerAbility.AllowFlying | PlayerAbility.Invulnerable,
Gamemode.Spectator => PlayerAbility.AllowFlying | PlayerAbility.Invulnerable,
Gamemode.Survival or Gamemode.Adventure or Gamemode.Hardcore => PlayerAbility.None,
_ => throw new ArgumentOutOfRangeException(nameof(Gamemode), Gamemode, "Unknown gamemode.")
};
}
}

public PlayerAbility Abilities { get; internal set; }

public IScoreboard? CurrentScoreboard { get; set; }

Expand Down Expand Up @@ -115,6 +133,8 @@ internal set

public IPAddress? ClientIP => (client.RemoteEndPoint as IPEndPoint)?.Address;

private Gamemode gamemode;

[SetsRequiredMembers]
internal Player(Guid uuid, string username, Client client, World world)
{
Expand Down
1 change: 1 addition & 0 deletions Obsidian/Net/ClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public void RegisterHandlers()
Packets.TryAdd(0x17, new SetPlayerPositionPacket());
Packets.TryAdd(0x18, new SetPlayerPositionAndRotationPacket());
Packets.TryAdd(0x19, new SetPlayerRotationPacket());
Packets.TryAdd(0x20, new PlayerAbilitiesPacket(false));
//Packets.TryAdd(0x15, PlayerMovement);
//Packets.TryAdd(0x16, VehicleMove);
//Packets.TryAdd(0x17, SteerBoat);
Expand Down
58 changes: 58 additions & 0 deletions Obsidian/Net/Packets/Play/Clientbound/PlayerAbilitiesPacket.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using Obsidian.API._Types;
using Obsidian.Entities;

namespace Obsidian.Net.Packets.Play.Clientbound;

public class PlayerAbilitiesPacket : IClientboundPacket, IServerboundPacket
{
public PlayerAbility Abilities { get; set; } = PlayerAbility.None;

public float FlyingSpeed { get; set; } = 0.05F;

public float FieldOfViewModifier { get; set; } = 0.1F;

public int Id { get; }

public PlayerAbilitiesPacket(bool toClient)
{
Id = toClient ? 0x36 : 0x20;
}

public void Serialize(MinecraftStream stream)
{
using var packetStream = new MinecraftStream();
packetStream.WriteByte((byte)Abilities);
packetStream.WriteFloat(FlyingSpeed);
packetStream.WriteFloat(FieldOfViewModifier);

stream.Lock.Wait();
stream.WriteVarInt(Id.GetVarIntLength() + (int)packetStream.Length);
stream.WriteVarInt(Id);
packetStream.Position = 0;
packetStream.CopyTo(stream);
stream.Lock.Release();
}

public void Populate(MinecraftStream stream)
{
Abilities = (PlayerAbility) stream.ReadByte();
}

public void Populate(byte[] data)
{
using var stream = new MinecraftStream(data);
Populate(stream);
}

public async ValueTask HandleAsync(Server server, Player player)
{
if (Abilities.HasFlag(PlayerAbility.Flying)
&& !Abilities.HasFlag(PlayerAbility.AllowFlying)
&& player.Gamemode is not Gamemode.Creative or Gamemode.Spectator)
{
await player.KickAsync("Cheating is not allowed!");
}

player.Abilities |= Abilities;
}
}
Loading