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

Container events #341

Merged
merged 10 commits into from
May 15, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 5 additions & 7 deletions Obsidian.API/Events/ContainerClickEventArgs.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
namespace Obsidian.API.Events;
using System.Diagnostics.CodeAnalysis;

public class ContainerClickEventArgs : PlayerEventArgs, ICancellable
{
/// <summary>
/// Gets the clicked container
/// </summary>
public BaseContainer Container { get; }
namespace Obsidian.API.Events;

public sealed class ContainerClickEventArgs : ContainerEventArgs, ICancellable
{
/// <summary>
/// Gets the current item that was clicked
/// </summary>
Expand All @@ -20,6 +17,7 @@ public class ContainerClickEventArgs : PlayerEventArgs, ICancellable
/// <inheritdoc />
public bool IsCancelled { get; private set; }

[SetsRequiredMembers]
internal ContainerClickEventArgs(IPlayer player, BaseContainer container, ItemStack item) : base(player)
{
this.Container = container;
Expand Down
11 changes: 11 additions & 0 deletions Obsidian.API/Events/ContainerClosedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Obsidian.API.Events;
public sealed class ContainerClosedEventArgs : ContainerEventArgs, ICancellable
{
public bool IsCancelled { get; private set; }

internal ContainerClosedEventArgs(IPlayer player) : base(player)
{
}

public void Cancel() => this.IsCancelled = true;
}
12 changes: 12 additions & 0 deletions Obsidian.API/Events/ContainerEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Diagnostics.CodeAnalysis;

namespace Obsidian.API.Events;

public class ContainerEventArgs : PlayerEventArgs
{
public required BaseContainer Container { get; init; }

protected ContainerEventArgs(IPlayer player) : base(player)
{
}
}
2 changes: 1 addition & 1 deletion Obsidian.API/Events/ICancellable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public interface ICancellable
/// <summary>
/// Sets a flag which prevents default (vanilla) behavior from executing.
/// </summary>
/// <remarks>This flag only affects vanilla behavior. If you wish to prevent other handlers from running, see <see cref="AsyncEventArgs.IsHandled"/>.</remarks>
/// <remarks>This flag only affects vanilla behavior. If you wish to prevent other handlers from running, see <see cref="AsyncEventArgs.Handled"/>.</remarks>
public void Cancel();
}
2 changes: 1 addition & 1 deletion Obsidian/Entities/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public sealed partial class Player : Living, IPlayer
public Container Inventory { get; }
public Container EnderInventory { get; }

public BaseContainer OpenedContainer { get; set; }
public BaseContainer? OpenedContainer { get; set; }

public List<SkinProperty> SkinProperties { get; set; } = new();

Expand Down
8 changes: 8 additions & 0 deletions Obsidian/Events/MinecraftEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class MinecraftEventHandler
public AsyncEvent<EntityInteractEventArgs> EntityInteract;
public AsyncEvent<PlayerAttackEntityEventArgs> PlayerAttackEntity;
public AsyncEvent<PlayerInteractEventArgs> PlayerInteract;
public AsyncEvent<ContainerClosedEventArgs> ContainerClosed;
public AsyncEvent ServerTick;

public MinecraftEventHandler()
Expand All @@ -40,6 +41,7 @@ public MinecraftEventHandler()
EntityInteract = new("EntityInteract", HandleException);
PlayerAttackEntity = new("PlayerAttackEntity", HandleException);
PlayerInteract = new("PlayerInteract", HandleException);
ContainerClosed = new("ContainerClosed", HandleException);
}

private void HandleException(AsyncEvent e, Exception exception)
Expand All @@ -50,6 +52,12 @@ private void HandleException<T>(AsyncEvent<T> e, Exception exception)
{
}

internal async ValueTask<ContainerClosedEventArgs> InvokeContainerClosedAsync(ContainerClosedEventArgs eventArgs)
{
await ContainerClosed.InvokeAsync(eventArgs);
return eventArgs;
}

internal async ValueTask<QueuePacketEventArgs> InvokeQueuePacketAsync(QueuePacketEventArgs eventArgs)
{
await QueuePacket.InvokeAsync(eventArgs);
Expand Down
42 changes: 3 additions & 39 deletions Obsidian/Net/Packets/Play/CloseContainerPacket.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Obsidian.API.Builders;
using Obsidian.API.Events;
using Obsidian.Entities;
using Obsidian.Net.Packets.Play.Clientbound;
using Obsidian.Serialization.Attributes;

namespace Obsidian.Net.Packets.Play;
Expand All @@ -14,44 +13,9 @@ public partial class CloseContainerPacket : IClientboundPacket, IServerboundPack

public async ValueTask HandleAsync(Server server, Player player)
{
if (WindowId == 0 || (player.OpenedContainer is not IBlockEntity tileEntity))
if (WindowId == 0)
return;

var position = tileEntity.BlockPosition;

var block = await player.World.GetBlockAsync(position);

if (block == null)
return;

if (block.Is(Material.Chest))
{
await player.client.QueuePacketAsync(new BlockActionPacket
{
Position = position,
ActionId = 1,
ActionParam = 0,
BlockType = block.BaseId
});

await player.SendSoundAsync(SoundEffectBuilder.Create(SoundId.BlockChestClose)
.WithSoundPosition(position.SoundPosition)
.Build());
}
else if (block.Is(Material.EnderChest))
{
await player.client.QueuePacketAsync(new BlockActionPacket
{
Position = position,
ActionId = 1,
ActionParam = 0,
BlockType = block.BaseId
});
await player.SendSoundAsync(SoundEffectBuilder.Create(SoundId.BlockEnderChestClose)
.WithSoundPosition(position.SoundPosition)
.Build());
}

player.OpenedContainer = null;
await server.Events.InvokeContainerClosedAsync(new ContainerClosedEventArgs(player) { Container = player.OpenedContainer! });
}
}
79 changes: 79 additions & 0 deletions Obsidian/Server.Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,85 @@ private async Task PlayerAttack(PlayerAttackEntityEventArgs e)
}
}

private async Task OnContainerClosed(ContainerClosedEventArgs e)
{
if (e.IsCancelled)
return;

var player = (e.Player as Player)!;

//Player successfully exited container
player.OpenedContainer = null;

if (e.Container is not IBlockEntity blockEntity)
return;

var position = blockEntity.BlockPosition;
var block = await e.Player.WorldLocation.GetBlockAsync(position);

if (block is null)
return;

switch (block.Material)
{
case Material.Chest:
{
await player.client.QueuePacketAsync(new BlockActionPacket
{
Position = position,
ActionId = 1,
ActionParam = 0,
BlockType = block.BaseId
});

await player.SendSoundAsync(SoundEffectBuilder.Create(SoundId.BlockChestClose)
.WithSoundPosition(position.SoundPosition)
.Build());

break;
}
case Material.EnderChest:
{
await player.client.QueuePacketAsync(new BlockActionPacket
{
Position = position,
ActionId = 1,
ActionParam = 0,
BlockType = block.BaseId
});

await player.SendSoundAsync(SoundEffectBuilder.Create(SoundId.BlockEnderChestClose)
.WithSoundPosition(position.SoundPosition)
.Build());
break;
}
case Material.Barrel://Barrels don't have a block action
{
await player.SendSoundAsync(SoundEffectBuilder.Create(SoundId.BlockBarrelClose)
.WithSoundPosition(position.SoundPosition)
.Build());

break;
}
case Material.ShulkerBox:
{
await player.client.QueuePacketAsync(new BlockActionPacket
{
Position = position,
ActionId = 1,
ActionParam = 0,
BlockType = block.BaseId
});

await player.SendSoundAsync(SoundEffectBuilder.Create(SoundId.BlockShulkerBoxClose)
.WithSoundPosition(position.SoundPosition)
.Build());

break;
}
}
}

private async Task OnPlayerInteract(PlayerInteractEventArgs e)
{
var item = e.Item;
Expand Down
1 change: 1 addition & 0 deletions Obsidian/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public static string VERSION
Events.PlayerJoin += OnPlayerJoin;
Events.PlayerAttackEntity += PlayerAttack;
Events.PlayerInteract += OnPlayerInteract;
Events.ContainerClosed += OnContainerClosed;

PersistentDataPath = Path.Combine(ServerFolderPath, "persistentdata");

Expand Down