Skip to content
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
2 changes: 1 addition & 1 deletion Obsidian.API/Events/BlockBreakEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class BlockBreakEventArgs : BlockEventArgs, ICancellable
/// <inheritdoc/>
public bool IsCancelled { get; private set; }

internal BlockBreakEventArgs(IServer server, IPlayer player, IBlock block, Vector location) : base(server, block, location)
internal BlockBreakEventArgs(IServer server, IPlayer player, IBlock block, Vector location, IWorld world) : base(server, block, location, world)
{
Player = player;
}
Expand Down
16 changes: 6 additions & 10 deletions Obsidian.API/Events/BlockEventArgs.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
namespace Obsidian.API.Events;

public abstract class BlockEventArgs : BaseMinecraftEventArgs
public abstract class BlockEventArgs(IServer server, IBlock block, Vector location, IWorld world) : BaseMinecraftEventArgs(server)
{
/// <summary>
/// The impacted block.
/// </summary>
public IBlock Block { get; }
public IBlock Block { get; } = block;

/// <summary>
/// Location of the impacted block.
/// </summary>
public Vector Location { get; }
public Vector Location { get; } = location;

/// <summary>
/// World where the event took place.
/// </summary>
public IWorld World { get; }
public IWorld World { get; } = world;

protected BlockEventArgs(IServer server, IBlock block, Vector location) : base(server)
{
Block = block;
Location = location;
World = server.DefaultWorld;
}

public int Sequence { get; init; }
}
9 changes: 2 additions & 7 deletions Obsidian.API/Events/PlayerLeaveEventArgs.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
namespace Obsidian.API.Events;

public class PlayerLeaveEventArgs : PlayerEventArgs
public class PlayerLeaveEventArgs(IPlayer player, IServer server, DateTimeOffset leave) : PlayerEventArgs(player, server)
{
/// <summary>
/// The date the player left.
/// </summary>
public DateTimeOffset LeaveDate { get; }

public PlayerLeaveEventArgs(IPlayer player, IServer server, DateTimeOffset leave) : base(player, server)
{
this.LeaveDate = leave;
}
public DateTimeOffset LeaveDate { get; } = leave;
}
4 changes: 2 additions & 2 deletions Obsidian.API/_Types/Velocity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public struct Velocity(double x, double y, double z)
/// <param name="z">How many blocks can be travelled on the Z axis in a second.</param>
public static Velocity FromBlockPerSecond(float x, float y, float z)
{
return new Velocity((short)(400f * x), (short)(400f * y), (short)(400f * z));
return new Velocity(x / 20f, y / 20f, z / 20f);
}

/// <summary>
Expand All @@ -45,7 +45,7 @@ public static Velocity FromBlockPerSecond(float x, float y, float z)
/// <param name="z">How many blocks can be travelled on the Z axis in a tick (50ms).</param>
public static Velocity FromBlockPerTick(float x, float y, float z)
{
return new Velocity((short)(8000f * x), (short)(8000f * y), (short)(8000f * z));
return new Velocity(x, y, z);
}

/// <summary>
Expand Down
8 changes: 7 additions & 1 deletion Obsidian/Entities/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,13 @@ public IScoreboard? CurrentScoreboard

public short CurrentHeldItemSlot
{
get => field;
get
{
if (field < 36 || field > 44)
field = 36;

return field;
}
set
{
if (value is < 0 or > 8)
Expand Down
67 changes: 67 additions & 0 deletions Obsidian/Events/MainEventHandler.World.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Obsidian.API.Events;
using Obsidian.Entities;
using Obsidian.Net.Packets.Play.Clientbound;

namespace Obsidian.Events;

public partial class MainEventHandler
{
[EventPriority(Priority = Priority.Internal)]
public async ValueTask OnBlockBreak(BlockBreakEventArgs args)
{
var player = args.Player;
var sequence = args.Sequence;
var block = args.Block;
var world = player.World;
var location = args.Location;

player.Client.SendPacket(new BlockChangedAckPacket
{
SequenceID = sequence
});

if (args.IsCancelled)
{
player.Client.SendPacket(new BlockUpdatePacket(location, block.GetHashCode()));
return;
}
Comment thread
Tides marked this conversation as resolved.

await world.SetBlockAsync(location, BlocksRegistry.Air, true);

player.Client.SendPacket(new BlockUpdatePacket(location, BlocksRegistry.Air.GetHashCode()));

world.PacketBroadcaster.QueuePacketToWorld(world, 0, new BlockDestructionPacket
{
EntityId = player.EntityId,
Position = location,
DestroyStage = -1
}, player.EntityId);

var droppedItem = ItemsRegistry.GetSingleItem(block.Material);

if (droppedItem.Type == Material.Air)
return;

var item = new ItemEntity
{
EntityId = Server.GetNextEntityId(),
Item = droppedItem,
World = player.World,
Position = (VectorF)location + 0.5f,
};

player.World.TryAddEntity(item);

var power = GetRandDropVelocity();
var direction = Globals.Random.NextFloat() * 6.2f;

item.SpawnEntity(new Velocity(-Math.Sin(direction) * power, 0.2f, Math.Cos(direction) * power));
}

private static float GetRandDropVelocity()
{
var f = Globals.Random.NextFloat();

return f * 0.5f;
}
}
2 changes: 0 additions & 2 deletions Obsidian/Events/MainEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,6 @@ public async Task OnPlayerLeave(PlayerLeaveEventArgs e)

await player.SaveAsync();

player.World.TryRemovePlayer(player);

packetBroadcaster.Broadcast(new PlayerInfoRemovePacket
{
UUIDs = [player.Uuid]
Expand Down
42 changes: 18 additions & 24 deletions Obsidian/Net/NetworkBuffer.Writing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@
using Obsidian.Nbt;
using Obsidian.Net.Packets.Play.Clientbound;
using Obsidian.Serialization.Attributes;
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;

Expand Down Expand Up @@ -561,15 +559,16 @@ public void WriteSoundEvent(SoundEvent soundEvent)
}

private const double MinAbsValue = 3.051944088384301E-5;
private const double MaxVelocityComponent = 1.7179869183E10;

[WriteMethod]
public void WriteVelocity(Velocity value)
{
var sanitizedX = Sanitize(value.X);
var sanitizedY = Sanitize(value.Y);
var sanitizedZ = Sanitize(value.Z);
var x = SanitizeVelocityComponent(value.X);
var y = SanitizeVelocityComponent(value.Y);
var z = SanitizeVelocityComponent(value.Z);

var maxAbsValue = NumericsHelper.AbsMax(sanitizedX, NumericsHelper.AbsMax(sanitizedY, sanitizedZ));
var maxAbsValue = NumericsHelper.AbsMax(x, NumericsHelper.AbsMax(y, z));

if (maxAbsValue < MinAbsValue)
{
Expand All @@ -578,16 +577,14 @@ public void WriteVelocity(Velocity value)
}

var scaleFactor = (long)Math.Ceiling(maxAbsValue);
var needsExtraBytes = (scaleFactor & ~3L) != 0; // Check if bits beyond the lower 2 are set
var adjustedScale = needsExtraBytes ? (scaleFactor & 3L) | 4L : scaleFactor;
var needsExtraBytes = (scaleFactor & 3L) != scaleFactor;
var packedScale = needsExtraBytes ? (scaleFactor & 3L) | 4L : scaleFactor;

var scale = (double)scaleFactor;
var packedX = PackVelocity(sanitizedX / scale) << 3;
var packedY = PackVelocity(sanitizedY / scale) << 18;
var packedZ = PackVelocity(sanitizedZ / scale) << 33;

var packedData = adjustedScale | packedX | packedY | packedZ;
var packedX = PackVelocityComponent(x / scaleFactor) << 3;
var packedY = PackVelocityComponent(y / scaleFactor) << 18;
var packedZ = PackVelocityComponent(z / scaleFactor) << 33;

var packedData = packedScale | packedX | packedY | packedZ;
this.WriteByte((byte)packedData);
this.WriteByte((byte)(packedData >> 8));
this.WriteInt((int)(packedData >> 16));
Expand Down Expand Up @@ -699,15 +696,12 @@ public void WriteOptional<TValue>(TValue? value) where TValue : INetworkSerializ
public byte[] ToArray() => this.Data;


[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long PackVelocity(double value)
{
const double scale = 0.5;
const int maxValue = short.MaxValue - 1;
return (long)Math.Round((value * scale + scale) * maxValue);
}
private const double VelocityPackingScale = 0.5;
private const int VelocityPackingMaxValue = short.MaxValue - 1;

private static long PackVelocityComponent(double value) =>
(long)Math.Round((value * VelocityPackingScale + VelocityPackingScale) * VelocityPackingMaxValue, MidpointRounding.AwayFromZero);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double Sanitize(double value) =>
double.IsNaN(value) ? 0.0 : Math.Clamp(value, -1.7179869183E10, 1.7179869183E10);
private static double SanitizeVelocityComponent(double value) =>
double.IsNaN(value) ? 0.0 : Math.Clamp(value, -MaxVelocityComponent, MaxVelocityComponent);
}
61 changes: 18 additions & 43 deletions Obsidian/Net/Packets/Play/Serverbound/PlayerActionPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,20 @@ public async override ValueTask HandleAsync(IServer server, IPlayer player)

if (Status == PlayerActionStatus.FinishedDigging || (Status == PlayerActionStatus.StartedDigging && player.Gamemode == Gamemode.Creative))
{
await player.World.SetBlockAsync(Position, BlocksRegistry.Air, true);
player.Client.SendPacket(new BlockChangedAckPacket
var args = new BlockBreakEventArgs(server, player, block, Position, player.World)
{
SequenceID = Sequence
});
Sequence = this.Sequence
};

var args = new BlockBreakEventArgs(server, player, block, Position);
await server.EventDispatcher.ExecuteEventAsync(args);
if (args.Handled)
return;

return;
}

this.BroadcastPlayerAction(player, block);
this.BroadcastPlayerAction(player);
Comment thread
Tides marked this conversation as resolved.
}

private void BroadcastPlayerAction(IPlayer player, IBlock block)
private void BroadcastPlayerAction(IPlayer player)
{
switch (this.Status)
{
Expand All @@ -66,52 +64,29 @@ private void BroadcastPlayerAction(IPlayer player, IBlock block)
}
case PlayerActionStatus.StartedDigging:
case PlayerActionStatus.CancelledDigging:
player.Client.SendPacket(new BlockChangedAckPacket
{
SequenceID = this.Sequence
});
break;
case PlayerActionStatus.FinishedDigging:
{
player.World.PacketBroadcaster.QueuePacketToWorld(player.World, 0, new BlockDestructionPacket
{
EntityId = player.EntityId,
Position = this.Position,
DestroyStage = -1
}, player.EntityId);

var droppedItem = ItemsRegistry.GetSingleItem(block.Material);

if (droppedItem.Type == Material.Air) { break; }

var item = new ItemEntity
{
EntityId = Server.GetNextEntityId(),
Item = droppedItem,
World = player.World,
Position = (VectorF)this.Position + 0.5f,
};

player.World.TryAddEntity(item);

item.SpawnEntity(Velocity.FromBlockPerTick(GetRandDropVelocity(), GetRandDropVelocity(), GetRandDropVelocity()));

break;
}
}
}

private static float GetRandDropVelocity()
{
var f = Globals.Random.NextFloat();

return f * 0.5f;
}

private static void DropItem(IPlayer player, sbyte amountToRemove)
{
var droppedItem = player.GetHeldItem();

if (droppedItem is null or { Type: Material.Air })
return;

var loc = new VectorF(player.Position.X, (float)player.HeadY - 0.3f, player.Position.Z);
var lookDir = player.GetLookDirection();
var loc = new VectorF(player.Position.X, (float)player.HeadY - 0.3f, player.Position.Z) + lookDir * 0.3f;

var item = new ItemEntity
{
Expand All @@ -123,9 +98,7 @@ private static void DropItem(IPlayer player, sbyte amountToRemove)

player.World.TryAddEntity(item);

var lookDir = player.GetLookDirection();

var vel = Velocity.FromDirection(loc, lookDir);//TODO properly shoot the item towards the direction the players looking at
var vel = Velocity.FromBlockPerTick(lookDir.X * 0.45f, lookDir.Y * 0.45f + 0.1f, lookDir.Z * 0.45f);

item.SpawnEntity(vel);

Expand Down Expand Up @@ -160,7 +133,9 @@ public enum PlayerActionStatus : int
DropItemStack,
DropItem,

ShootArrowOrFinishEating,
ReleaseUseItem,

SwapItemInHand,

SwapItemInHand
Stab
}
2 changes: 2 additions & 0 deletions Obsidian/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ public bool RemovePlayer(IPlayer player)
{
this.UsernameToUuidMappings.Remove(player.Username, out _);

player.World.TryRemovePlayer(player);

return this.OnlinePlayers.Remove(player.Uuid, out _);
}

Expand Down
1 change: 0 additions & 1 deletion Obsidian/Utilities/NumericsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,5 @@ public static void LongToInts(long l, out int a, out int b)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Modulo(int x, int mod) => (x % mod + mod) % mod;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double AbsMax(double a, double b) => Math.Max(Math.Abs(a), Math.Abs(b));
}
2 changes: 1 addition & 1 deletion Obsidian/WorldData/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public async ValueTask SetBlockAsync(int x, int y, int z, IBlock block, bool doB
private void BroadcastBlockChange(IBlock block, Vector location)
{
var packet = new BlockUpdatePacket(location, block.GetHashCode());
foreach (Player player in this.PlayersInRange(location))
foreach (Player player in PlayersInRange(location).Cast<Player>())
{
player.Client.SendPacket(packet);
}
Expand Down
Loading