mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-04 23:47:59 +01:00
Fix testing (v2) (#99)
* Fix Minecraft changes since 1.19 (Block.GRASS, recipe packet, DamageType.VOID)
* Add packets in play state
* Fix some tests via TestConnectionImpl and API changes
* fix: add some missing entity metas, group projectiles
---------
Co-authored-by: GoldenStack <goldenfire64yt@gmail.com>
(cherry picked from commit 89a665fdf5
)
This commit is contained in:
parent
ed13961e90
commit
58b550c5ff
@ -9,7 +9,7 @@ import net.minestom.server.command.builder.condition.Conditions;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.entity.metadata.arrow.ArrowMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.ArrowMeta;
|
||||
import net.minestom.server.entity.EntityProjectile;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
@ -1842,6 +1842,9 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev
|
||||
ROARING,
|
||||
SNIFFING,
|
||||
EMERGING,
|
||||
DIGGING
|
||||
DIGGING,
|
||||
SLIDING,
|
||||
SHOOTING,
|
||||
INHALING;
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import net.minestom.server.collision.BoundingBox;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.ProjectileMeta;
|
||||
import net.minestom.server.event.EventDispatcher;
|
||||
import net.minestom.server.event.entity.EntityShootEvent;
|
||||
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
|
||||
|
@ -7,9 +7,7 @@ import net.minestom.server.entity.metadata.animal.*;
|
||||
import net.minestom.server.entity.metadata.animal.tameable.CatMeta;
|
||||
import net.minestom.server.entity.metadata.animal.tameable.ParrotMeta;
|
||||
import net.minestom.server.entity.metadata.animal.tameable.WolfMeta;
|
||||
import net.minestom.server.entity.metadata.arrow.ArrowMeta;
|
||||
import net.minestom.server.entity.metadata.arrow.SpectralArrowMeta;
|
||||
import net.minestom.server.entity.metadata.arrow.ThrownTridentMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.*;
|
||||
import net.minestom.server.entity.metadata.display.BlockDisplayMeta;
|
||||
import net.minestom.server.entity.metadata.display.ItemDisplayMeta;
|
||||
import net.minestom.server.entity.metadata.display.TextDisplayMeta;
|
||||
@ -33,10 +31,7 @@ import net.minestom.server.entity.metadata.water.AxolotlMeta;
|
||||
import net.minestom.server.entity.metadata.water.DolphinMeta;
|
||||
import net.minestom.server.entity.metadata.water.GlowSquidMeta;
|
||||
import net.minestom.server.entity.metadata.water.SquidMeta;
|
||||
import net.minestom.server.entity.metadata.water.fish.CodMeta;
|
||||
import net.minestom.server.entity.metadata.water.fish.PufferfishMeta;
|
||||
import net.minestom.server.entity.metadata.water.fish.SalmonMeta;
|
||||
import net.minestom.server.entity.metadata.water.fish.TropicalFishMeta;
|
||||
import net.minestom.server.entity.metadata.water.fish.*;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -78,7 +73,7 @@ record EntityTypeImpl(Registry.EntityEntry registry) implements EntityType {
|
||||
|
||||
private static Map<String, BiFunction<Entity, Metadata, EntityMeta>> createMetaMap() {
|
||||
return Map.<String, BiFunction<Entity, Metadata, EntityMeta>>ofEntries(
|
||||
entry("minecraft:allay", EntityMeta::new), // TODO dedicated metadata
|
||||
entry("minecraft:allay", AllayMeta::new),
|
||||
entry("minecraft:area_effect_cloud", AreaEffectCloudMeta::new),
|
||||
entry("minecraft:armor_stand", ArmorStandMeta::new),
|
||||
entry("minecraft:arrow", ArrowMeta::new),
|
||||
@ -88,6 +83,7 @@ record EntityTypeImpl(Registry.EntityEntry registry) implements EntityType {
|
||||
entry("minecraft:blaze", BlazeMeta::new),
|
||||
entry("minecraft:block_display", BlockDisplayMeta::new),
|
||||
entry("minecraft:boat", BoatMeta::new),
|
||||
entry("minecraft:breeze", BreezeMeta::new),
|
||||
entry("minecraft:chest_boat", BoatMeta::new),
|
||||
entry("minecraft:camel", CamelMeta::new),
|
||||
entry("minecraft:cat", CatMeta::new),
|
||||
@ -176,7 +172,7 @@ record EntityTypeImpl(Registry.EntityEntry registry) implements EntityType {
|
||||
entry("minecraft:squid", SquidMeta::new),
|
||||
entry("minecraft:stray", StrayMeta::new),
|
||||
entry("minecraft:strider", StriderMeta::new),
|
||||
entry("minecraft:tadpole", EntityMeta::new), // TODO dedicated metadata
|
||||
entry("minecraft:tadpole", TadpoleMeta::new),
|
||||
entry("minecraft:egg", ThrownEggMeta::new),
|
||||
entry("minecraft:ender_pearl", ThrownEnderPearlMeta::new),
|
||||
entry("minecraft:experience_bottle", ThrownExperienceBottleMeta::new),
|
||||
@ -190,6 +186,7 @@ record EntityTypeImpl(Registry.EntityEntry registry) implements EntityType {
|
||||
entry("minecraft:vindicator", VindicatorMeta::new),
|
||||
entry("minecraft:wandering_trader", WanderingTraderMeta::new),
|
||||
entry("minecraft:warden", WardenMeta::new),
|
||||
entry("minecraft:wind_charge", WindChargeMeta::new),
|
||||
entry("minecraft:witch", WitchMeta::new),
|
||||
entry("minecraft:wither", WitherMeta::new),
|
||||
entry("minecraft:wither_skeleton", WitherSkeletonMeta::new),
|
||||
|
@ -7,7 +7,7 @@ import net.minestom.server.collision.ShapeImpl;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.ProjectileMeta;
|
||||
import net.minestom.server.event.EventDispatcher;
|
||||
import net.minestom.server.event.entity.EntityShootEvent;
|
||||
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
|
||||
|
@ -3,7 +3,7 @@ package net.minestom.server.entity.metadata.item;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.ObjectDataProvider;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.ProjectileMeta;
|
||||
import net.minestom.server.item.Material;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -3,7 +3,7 @@ package net.minestom.server.entity.metadata.item;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.ObjectDataProvider;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.ProjectileMeta;
|
||||
import net.minestom.server.item.Material;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -0,0 +1,15 @@
|
||||
package net.minestom.server.entity.metadata.monster;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BreezeMeta extends MonsterMeta {
|
||||
public static final byte OFFSET = MonsterMeta.MAX_OFFSET;
|
||||
public static final byte MAX_OFFSET = OFFSET + 0;
|
||||
|
||||
public BreezeMeta(@NotNull Entity entity, @NotNull Metadata metadata) {
|
||||
super(entity, metadata);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package net.minestom.server.entity.metadata.other;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.PathfinderMobMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AllayMeta extends PathfinderMobMeta {
|
||||
public static final byte OFFSET = PathfinderMobMeta.MAX_OFFSET;
|
||||
public static final byte MAX_OFFSET = OFFSET + 2;
|
||||
|
||||
public AllayMeta(@NotNull Entity entity, @NotNull Metadata metadata) {
|
||||
super(entity, metadata);
|
||||
}
|
||||
|
||||
|
||||
public boolean isDancing() {
|
||||
return super.metadata.getIndex(OFFSET, false);
|
||||
}
|
||||
|
||||
public void setDancing(boolean value) {
|
||||
super.metadata.setIndex(OFFSET, Metadata.Boolean(value));
|
||||
}
|
||||
|
||||
|
||||
public boolean canDuplicate() {
|
||||
return super.metadata.getIndex(OFFSET + 1, true);
|
||||
}
|
||||
|
||||
public void setCanDuplicate(boolean value) {
|
||||
super.metadata.setIndex(OFFSET + 1, Metadata.Boolean(value));
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net.minestom.server.entity.metadata.arrow;
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
@ -1,9 +1,8 @@
|
||||
package net.minestom.server.entity.metadata.arrow;
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.ObjectDataProvider;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -1,10 +1,10 @@
|
||||
package net.minestom.server.entity.metadata.other;
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.EntityMeta;
|
||||
import net.minestom.server.entity.metadata.ObjectDataProvider;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.ProjectileMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.minestom.server.entity.metadata.other;
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.EntityMeta;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.ProjectileMeta;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
@ -1,4 +1,4 @@
|
||||
package net.minestom.server.entity.metadata;
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import org.jetbrains.annotations.Nullable;
|
@ -1,9 +1,8 @@
|
||||
package net.minestom.server.entity.metadata.arrow;
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.ObjectDataProvider;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.minestom.server.entity.metadata.arrow;
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
@ -0,0 +1,40 @@
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.EntityMeta;
|
||||
import net.minestom.server.entity.metadata.ObjectDataProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class WindChargeMeta extends EntityMeta implements ObjectDataProvider, ProjectileMeta {
|
||||
public static final byte OFFSET = EntityMeta.MAX_OFFSET;
|
||||
public static final byte MAX_OFFSET = OFFSET + 0;
|
||||
|
||||
private Entity shooter;
|
||||
|
||||
public WindChargeMeta(@NotNull Entity entity, @NotNull Metadata metadata) {
|
||||
super(entity, metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entity getShooter() {
|
||||
return shooter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShooter(@Nullable Entity shooter) {
|
||||
this.shooter = shooter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjectData() {
|
||||
return this.shooter == null ? 0 : this.shooter.getEntityId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresVelocityPacketAtSpawn() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package net.minestom.server.entity.metadata.other;
|
||||
package net.minestom.server.entity.metadata.projectile;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.EntityMeta;
|
||||
import net.minestom.server.entity.metadata.ObjectDataProvider;
|
||||
import net.minestom.server.entity.metadata.ProjectileMeta;
|
||||
import net.minestom.server.entity.metadata.projectile.ProjectileMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -0,0 +1,15 @@
|
||||
package net.minestom.server.entity.metadata.water.fish;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class TadpoleMeta extends AbstractFishMeta {
|
||||
public static final byte OFFSET = AbstractFishMeta.MAX_OFFSET;
|
||||
public static final byte MAX_OFFSET = OFFSET + 0;
|
||||
|
||||
public TadpoleMeta(@NotNull Entity entity, @NotNull Metadata metadata) {
|
||||
super(entity, metadata);
|
||||
}
|
||||
|
||||
}
|
@ -208,7 +208,7 @@ public final class ConnectionManager {
|
||||
|
||||
@ApiStatus.Internal
|
||||
public void transitionLoginToConfig(@NotNull Player player) {
|
||||
AsyncUtils.runAsync(() -> {
|
||||
CompletableFuture<Void> configFuture = AsyncUtils.runAsync(() -> {
|
||||
final PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
|
||||
// Compression
|
||||
@ -240,6 +240,7 @@ public final class ConnectionManager {
|
||||
playerConnection.sendPacket(loginSuccessPacket);
|
||||
configurationPlayers.add(player);
|
||||
});
|
||||
if (DebugUtils.INSIDE_TEST) configFuture.join();
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@ -250,7 +251,7 @@ public final class ConnectionManager {
|
||||
|
||||
@ApiStatus.Internal
|
||||
public void doConfiguration(@NotNull Player player, boolean isFirstConfig) {
|
||||
AsyncUtils.runAsync(() -> {
|
||||
CompletableFuture<Void> configFuture = AsyncUtils.runAsync(() -> {
|
||||
player.sendPacket(PluginMessagePacket.getBrandPacket());
|
||||
|
||||
var event = new AsyncPlayerConfigurationEvent(player, isFirstConfig);
|
||||
@ -274,6 +275,7 @@ public final class ConnectionManager {
|
||||
player.setPendingInstance(spawningInstance);
|
||||
player.sendPacket(new FinishConfigurationPacket());
|
||||
});
|
||||
if (DebugUtils.INSIDE_TEST) configFuture.join();
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@ -321,7 +323,8 @@ public final class ConnectionManager {
|
||||
/**
|
||||
* Connects waiting players.
|
||||
*/
|
||||
private void updateWaitingPlayers() {
|
||||
@ApiStatus.Internal
|
||||
public void updateWaitingPlayers() {
|
||||
this.waitingPlayers.drain(player -> {
|
||||
configurationPlayers.remove(player);
|
||||
playPlayers.add(player);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.command;
|
||||
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.testing.Env;
|
||||
import net.minestom.testing.EnvTest;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
@ -40,7 +41,7 @@ public class CommandSuggestionIntegrationTest {
|
||||
env.process().command().register(command);
|
||||
|
||||
var listener = connection.trackIncoming(TabCompletePacket.class);
|
||||
player.addPacketToQueue(new ClientTabCompletePacket(3, "test te"));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientTabCompletePacket(3, "test te"));
|
||||
player.interpretPacketQueue();
|
||||
|
||||
listener.assertSingle(tabCompletePacket -> {
|
||||
@ -68,7 +69,7 @@ public class CommandSuggestionIntegrationTest {
|
||||
env.process().command().register(command);
|
||||
|
||||
var listener = connection.trackIncoming(TabCompletePacket.class);
|
||||
player.addPacketToQueue(new ClientTabCompletePacket(1, "foo 1"));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientTabCompletePacket(1, "foo 1"));
|
||||
player.interpretPacketQueue();
|
||||
|
||||
listener.assertSingle(tabCompletePacket -> {
|
||||
|
@ -135,7 +135,7 @@ public class CommandSyntaxSingleTest {
|
||||
context1.setArg("enchant", Enchantment.SHARPNESS, "minecraft:sharpness");
|
||||
context1.setArg("block", Block.STONE, "minecraft:stone");
|
||||
|
||||
context2.setArg("block", Block.GRASS, "minecraft:grass");
|
||||
context2.setArg("block", Block.GRASS_BLOCK, "minecraft:grass_block");
|
||||
context2.setArg("enchant", Enchantment.EFFICIENCY, "minecraft:efficiency");
|
||||
|
||||
var input = context1.getInput() + " " + context2.getInput();
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.entity;
|
||||
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.testing.Env;
|
||||
import net.minestom.testing.EnvTest;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
@ -24,7 +25,7 @@ public class PlayerHeldIntegrationTest {
|
||||
assertEquals(ItemStack.AIR, player.getItemInMainHand());
|
||||
assertEquals(0, player.getHeldSlot());
|
||||
|
||||
player.addPacketToQueue(new ClientHeldItemChangePacket((short) 1));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientHeldItemChangePacket((short) 1));
|
||||
player.interpretPacketQueue();
|
||||
|
||||
assertEquals(ItemStack.of(Material.STONE), player.getItemInMainHand());
|
||||
@ -41,7 +42,7 @@ public class PlayerHeldIntegrationTest {
|
||||
assertEquals(ItemStack.AIR, player.getItemInMainHand());
|
||||
assertEquals(0, player.getHeldSlot());
|
||||
|
||||
player.addPacketToQueue(new ClientHeldItemChangePacket((short) 1));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientHeldItemChangePacket((short) 1));
|
||||
var listener = env.listen(PlayerChangeHeldSlotEvent.class);
|
||||
listener.followup(event -> {
|
||||
assertEquals(player, event.getPlayer());
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.entity.player;
|
||||
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.testing.Env;
|
||||
import net.minestom.testing.EnvTest;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
@ -38,7 +39,7 @@ public class PlayerBlockPlacementIntegrationTest {
|
||||
1f, 1f, 1f,
|
||||
false, 0
|
||||
);
|
||||
player.addPacketToQueue(packet);
|
||||
player.addPacketToQueue(ConnectionState.PLAY, packet);
|
||||
player.interpretPacketQueue();
|
||||
|
||||
var placedBlock = instance.getBlock(1, 41, 0);
|
||||
|
@ -4,6 +4,7 @@ import net.minestom.server.event.player.PlayerGameModeChangeEvent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.entity.damage.DamageType;
|
||||
import net.minestom.server.message.ChatMessageType;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.client.common.ClientSettingsPacket;
|
||||
import net.minestom.testing.Collector;
|
||||
import net.minestom.testing.Env;
|
||||
@ -84,7 +85,7 @@ public class PlayerIntegrationTest {
|
||||
env.tick();
|
||||
env.tick();
|
||||
|
||||
player.addPacketToQueue(packet);
|
||||
player.addPacketToQueue(ConnectionState.PLAY, packet);
|
||||
var collector = connection.trackIncoming();
|
||||
env.tick();
|
||||
env.tick();
|
||||
@ -188,7 +189,7 @@ public class PlayerIntegrationTest {
|
||||
var player = connection.connect(instance, new Pos(5, 42, 2)).join();
|
||||
|
||||
assertNull(player.getDeathLocation());
|
||||
player.damage(DamageType.VOID, 30);
|
||||
player.damage(DamageType.OUT_OF_WORLD, 30);
|
||||
|
||||
assertNotNull(player.getDeathLocation());
|
||||
assertEquals(dimensionNamespace, player.getDeathLocation().dimension());
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.entity.player;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.testing.Collector;
|
||||
import net.minestom.testing.Env;
|
||||
import net.minestom.testing.EnvTest;
|
||||
@ -33,12 +34,12 @@ public class PlayerMovementIntegrationTest {
|
||||
var instance = env.createFlatInstance();
|
||||
var p1 = env.createPlayer(instance, new Pos(0, 40, 0));
|
||||
// No confirmation
|
||||
p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
|
||||
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
|
||||
p1.interpretPacketQueue();
|
||||
assertEquals(new Pos(0, 40, 0), p1.getPosition());
|
||||
// Confirmation
|
||||
p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
|
||||
p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
|
||||
p1.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
|
||||
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
|
||||
p1.interpretPacketQueue();
|
||||
assertEquals(new Pos(0.2, 40, 0), p1.getPosition());
|
||||
}
|
||||
@ -51,9 +52,9 @@ public class PlayerMovementIntegrationTest {
|
||||
var p1 = env.createPlayer(instance, new Pos(0, 40, 0));
|
||||
connection.connect(instance, new Pos(0, 40, 0)).join();
|
||||
|
||||
p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
|
||||
p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
|
||||
p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true));
|
||||
p1.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
|
||||
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
|
||||
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true));
|
||||
var tracker = connection.trackIncoming(EntityPositionPacket.class);
|
||||
p1.interpretPacketQueue();
|
||||
|
||||
@ -75,42 +76,42 @@ public class PlayerMovementIntegrationTest {
|
||||
final Player player = future.join();
|
||||
// Initial join
|
||||
chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter));
|
||||
player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId()));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(player.getLastSentTeleportId()));
|
||||
|
||||
// Move to next chunk
|
||||
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
|
||||
player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, 0.5), true));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(-0.5, 40, 0.5), true));
|
||||
player.interpretPacketQueue();
|
||||
chunkDataPacketCollector.assertCount(viewDiameter);
|
||||
|
||||
// Move to next chunk
|
||||
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
|
||||
player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, -0.5), true));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(-0.5, 40, -0.5), true));
|
||||
player.interpretPacketQueue();
|
||||
chunkDataPacketCollector.assertCount(viewDiameter);
|
||||
|
||||
// Move to next chunk
|
||||
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
|
||||
player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true));
|
||||
player.interpretPacketQueue();
|
||||
chunkDataPacketCollector.assertCount(viewDiameter);
|
||||
|
||||
// Move to next chunk
|
||||
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
|
||||
player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, 0.5), true));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(0.5, 40, 0.5), true));
|
||||
player.interpretPacketQueue();
|
||||
chunkDataPacketCollector.assertEmpty();
|
||||
|
||||
// Move to next chunk
|
||||
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
|
||||
player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true));
|
||||
player.interpretPacketQueue();
|
||||
chunkDataPacketCollector.assertEmpty();
|
||||
|
||||
// Move to next chunk
|
||||
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
|
||||
// Abuse the fact that there is no delta check
|
||||
player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(16.5, 40, -16.5), true));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(16.5, 40, -16.5), true));
|
||||
player.interpretPacketQueue();
|
||||
chunkDataPacketCollector.assertCount(viewDiameter * 2 - 1);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.minestom.server.entity.player;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.client.play.ClientStatusPacket;
|
||||
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
||||
import net.minestom.server.network.packet.server.play.UnloadChunkPacket;
|
||||
@ -57,7 +58,7 @@ public class PlayerRespawnChunkIntegrationTest {
|
||||
|
||||
var loadChunkTracker = connection.trackIncoming(ChunkDataPacket.class);
|
||||
player.setHealth(0);
|
||||
player.addPacketToQueue(new ClientStatusPacket(ClientStatusPacket.Action.PERFORM_RESPAWN));
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientStatusPacket(ClientStatusPacket.Action.PERFORM_RESPAWN));
|
||||
player.interpretPacketQueue();
|
||||
List<ChunkDataPacket> dataPacketList = loadChunkTracker.collect();
|
||||
Set<ChunkDataPacket> duplicateCheck = new HashSet<>();
|
||||
|
@ -22,7 +22,7 @@ public class BlockClientNbtTest {
|
||||
@Test
|
||||
public void basic() {
|
||||
assertNull(BlockUtils.extractClientNbt(Block.STONE));
|
||||
assertNull(BlockUtils.extractClientNbt(Block.GRASS));
|
||||
assertNull(BlockUtils.extractClientNbt(Block.GRASS_BLOCK));
|
||||
assertEquals(NBTCompound.EMPTY, BlockUtils.extractClientNbt(Block.CHEST));
|
||||
|
||||
var nbt = NBT.Compound(Map.of("test", NBT.String("test")));
|
||||
|
@ -82,7 +82,7 @@ public class GeneratorForkConsumerIntegrationTest {
|
||||
assertEquals(0, dynamic.height);
|
||||
assertEquals(0, dynamic.depth);
|
||||
setter.setBlock(unit.absoluteStart(), Block.STONE);
|
||||
setter.setBlock(unit.absoluteStart().add(0, 0, 16), Block.GRASS);
|
||||
setter.setBlock(unit.absoluteStart().add(0, 0, 16), Block.GRASS_BLOCK);
|
||||
assertEquals(unit.absoluteStart(), dynamic.minSection);
|
||||
assertEquals(1, dynamic.width);
|
||||
assertEquals(1, dynamic.height);
|
||||
@ -93,7 +93,7 @@ public class GeneratorForkConsumerIntegrationTest {
|
||||
instance.setGenerator(null);
|
||||
instance.loadChunk(0, 1).join();
|
||||
assertEquals(Block.STONE, instance.getBlock(0, -64, 0));
|
||||
assertEquals(Block.GRASS, instance.getBlock(0, -64, 16));
|
||||
assertEquals(Block.GRASS_BLOCK, instance.getBlock(0, -64, 16));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -108,7 +108,7 @@ public class GeneratorForkConsumerIntegrationTest {
|
||||
assertEquals(0, dynamic.height);
|
||||
assertEquals(0, dynamic.depth);
|
||||
setter.setBlock(unit.absoluteStart(), Block.STONE);
|
||||
setter.setBlock(unit.absoluteStart().add(16, 0, 0), Block.GRASS);
|
||||
setter.setBlock(unit.absoluteStart().add(16, 0, 0), Block.GRASS_BLOCK);
|
||||
assertEquals(unit.absoluteStart(), dynamic.minSection);
|
||||
assertEquals(2, dynamic.width);
|
||||
assertEquals(1, dynamic.height);
|
||||
@ -119,7 +119,7 @@ public class GeneratorForkConsumerIntegrationTest {
|
||||
instance.setGenerator(null);
|
||||
instance.loadChunk(1, 0).join();
|
||||
assertEquals(Block.STONE, instance.getBlock(0, -64, 0));
|
||||
assertEquals(Block.GRASS, instance.getBlock(16, -64, 0));
|
||||
assertEquals(Block.GRASS_BLOCK, instance.getBlock(16, -64, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -134,7 +134,7 @@ public class GeneratorForkConsumerIntegrationTest {
|
||||
assertEquals(0, dynamic.height);
|
||||
assertEquals(0, dynamic.depth);
|
||||
setter.setBlock(unit.absoluteStart(), Block.STONE);
|
||||
setter.setBlock(unit.absoluteStart().add(0, 16, 0), Block.GRASS);
|
||||
setter.setBlock(unit.absoluteStart().add(0, 16, 0), Block.GRASS_BLOCK);
|
||||
assertEquals(unit.absoluteStart(), dynamic.minSection);
|
||||
assertEquals(1, dynamic.width);
|
||||
assertEquals(2, dynamic.height);
|
||||
@ -143,7 +143,7 @@ public class GeneratorForkConsumerIntegrationTest {
|
||||
});
|
||||
instance.loadChunk(0, 0).join();
|
||||
assertEquals(Block.STONE, instance.getBlock(0, -64, 0));
|
||||
assertEquals(Block.GRASS, instance.getBlock(0, -48, 0));
|
||||
assertEquals(Block.GRASS_BLOCK, instance.getBlock(0, -48, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -22,8 +22,8 @@ public class InstanceBlockIntegrationTest {
|
||||
instance.loadChunk(0, 0).join();
|
||||
assertEquals(Block.AIR, instance.getBlock(0, 50, 0));
|
||||
|
||||
instance.setBlock(0, 50, 0, Block.GRASS);
|
||||
assertEquals(Block.GRASS, instance.getBlock(0, 50, 0));
|
||||
instance.setBlock(0, 50, 0, Block.GRASS_BLOCK);
|
||||
assertEquals(Block.GRASS_BLOCK, instance.getBlock(0, 50, 0));
|
||||
|
||||
instance.setBlock(0, 50, 0, Block.STONE);
|
||||
assertEquals(Block.STONE, instance.getBlock(0, 50, 0));
|
||||
@ -39,8 +39,8 @@ public class InstanceBlockIntegrationTest {
|
||||
var instance = env.createFlatInstance();
|
||||
instance.loadChunk(0, 0).join();
|
||||
|
||||
instance.setBlock(0, 50, 0, Block.GRASS);
|
||||
assertEquals(Block.GRASS, instance.getBlock(0, 50, 0));
|
||||
instance.setBlock(0, 50, 0, Block.GRASS_BLOCK);
|
||||
assertEquals(Block.GRASS_BLOCK, instance.getBlock(0, 50, 0));
|
||||
|
||||
instance.unloadChunk(0, 0);
|
||||
assertThrows(NullPointerException.class, () -> instance.getBlock(0, 0, 0),
|
||||
@ -70,7 +70,7 @@ public class InstanceBlockIntegrationTest {
|
||||
assertEquals(7, instance.getBlock(point).getTag(tag));
|
||||
|
||||
// Different block type
|
||||
instance.setBlock(point, Block.GRASS.withTag(tag, 8));
|
||||
instance.setBlock(point, Block.GRASS_BLOCK.withTag(tag, 8));
|
||||
assertEquals(8, instance.getBlock(point).getTag(tag));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.inventory.click.integration;
|
||||
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.testing.Env;
|
||||
import net.minestom.testing.EnvTest;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
@ -183,7 +184,7 @@ public class HeldClickIntegrationTest {
|
||||
slot = slot - 9 + offset;
|
||||
}
|
||||
}
|
||||
player.addPacketToQueue(new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) target,
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) target,
|
||||
ClientClickWindowPacket.ClickType.SWAP, List.of(), ItemStack.AIR));
|
||||
player.interpretPacketQueue();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.inventory.click.integration;
|
||||
|
||||
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.testing.Env;
|
||||
import net.minestom.testing.EnvTest;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
@ -166,7 +167,7 @@ public class LeftClickIntegrationTest {
|
||||
slot = slot - 9 + offset;
|
||||
}
|
||||
}
|
||||
player.addPacketToQueue(new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) 0,
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) 0,
|
||||
ClientClickWindowPacket.ClickType.PICKUP, List.of(), ItemStack.AIR));
|
||||
player.interpretPacketQueue();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.inventory.click.integration;
|
||||
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.testing.Env;
|
||||
import net.minestom.testing.EnvTest;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
@ -187,7 +188,7 @@ public class RightClickIntegrationTest {
|
||||
slot = slot - 9 + offset;
|
||||
}
|
||||
}
|
||||
player.addPacketToQueue(new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) 1,
|
||||
player.addPacketToQueue(ConnectionState.PLAY, new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) 1,
|
||||
ClientClickWindowPacket.ClickType.PICKUP, List.of(), ItemStack.AIR));
|
||||
player.interpretPacketQueue();
|
||||
}
|
||||
|
@ -30,15 +30,15 @@ public class SendablePacketTest {
|
||||
public void cached() {
|
||||
var packet = new SystemChatPacket(Component.text("Hello World!"), false);
|
||||
var cached = new CachedPacket(packet);
|
||||
assertSame(packet, cached.packet());
|
||||
assertSame(packet, cached.packet(ConnectionState.PLAY));
|
||||
|
||||
var buffer = PacketUtils.allocateTrimmedPacket(packet);
|
||||
var cachedBuffer = cached.body();
|
||||
var buffer = PacketUtils.allocateTrimmedPacket(ConnectionState.PLAY, packet);
|
||||
var cachedBuffer = cached.body(ConnectionState.PLAY);
|
||||
assertEquals(buffer.body(), cachedBuffer);
|
||||
// May fail in the very unlikely case where soft references are cleared
|
||||
// Rare enough to make this test worth it
|
||||
assertSame(cached.body(), cachedBuffer);
|
||||
assertSame(cached.body(ConnectionState.PLAY), cachedBuffer);
|
||||
|
||||
assertSame(packet, cached.packet());
|
||||
assertSame(packet, cached.packet(ConnectionState.PLAY));
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class SocketWriteTest {
|
||||
var packet = new IntPacket(5);
|
||||
|
||||
var buffer = ObjectPool.PACKET_POOL.get();
|
||||
PacketUtils.writeFramedPacket(buffer, packet, false);
|
||||
PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, false);
|
||||
|
||||
// 3 bytes length [var-int] + 1 byte packet id [var-int] + 4 bytes int
|
||||
// The 3 bytes var-int length is hardcoded for performance purpose, could change in the future
|
||||
@ -57,8 +57,8 @@ public class SocketWriteTest {
|
||||
var packet = new IntPacket(5);
|
||||
|
||||
var buffer = ObjectPool.PACKET_POOL.get();
|
||||
PacketUtils.writeFramedPacket(buffer, packet, false);
|
||||
PacketUtils.writeFramedPacket(buffer, packet, false);
|
||||
PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, false);
|
||||
PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, false);
|
||||
|
||||
// 3 bytes length [var-int] + 1 byte packet id [var-int] + 4 bytes int
|
||||
// The 3 bytes var-int length is hardcoded for performance purpose, could change in the future
|
||||
@ -74,7 +74,7 @@ public class SocketWriteTest {
|
||||
var packet = new CompressiblePacket(string);
|
||||
|
||||
var buffer = ObjectPool.PACKET_POOL.get();
|
||||
PacketUtils.writeFramedPacket(buffer, packet, true);
|
||||
PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, true);
|
||||
|
||||
// 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + payload
|
||||
// The 3 bytes var-int length is hardcoded for performance purpose, could change in the future
|
||||
@ -86,7 +86,7 @@ public class SocketWriteTest {
|
||||
var packet = new IntPacket(5);
|
||||
|
||||
var buffer = ObjectPool.PACKET_POOL.get();
|
||||
PacketUtils.writeFramedPacket(buffer, packet, true);
|
||||
PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, true);
|
||||
|
||||
// 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + 4 bytes int
|
||||
// The 3 bytes var-int length is hardcoded for performance purpose, could change in the future
|
||||
@ -98,8 +98,8 @@ public class SocketWriteTest {
|
||||
var packet = new IntPacket(5);
|
||||
|
||||
var buffer = ObjectPool.PACKET_POOL.get();
|
||||
PacketUtils.writeFramedPacket(buffer, packet, true);
|
||||
PacketUtils.writeFramedPacket(buffer, packet, true);
|
||||
PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, true);
|
||||
PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, true);
|
||||
|
||||
// 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + 4 bytes int
|
||||
// The 3 bytes var-int length is hardcoded for performance purpose, could change in the future
|
||||
|
@ -5,7 +5,9 @@ import net.minestom.server.ServerProcess;
|
||||
import net.minestom.server.adventure.MinestomAdventure;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
|
||||
import net.minestom.server.network.packet.server.SendablePacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
@ -34,17 +36,20 @@ final class TestConnectionImpl implements TestConnection {
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<Player> connect(@NotNull Instance instance, @NotNull Pos pos) {
|
||||
Player player = new Player(UUID.randomUUID(), "RandName", playerConnection);
|
||||
player.eventNode().addListener(PlayerLoginEvent.class, event -> {
|
||||
playerConnection.setServerState(ConnectionState.LOGIN);
|
||||
var player = process.connection().createPlayer(playerConnection, UUID.randomUUID(), "RandName");
|
||||
player.eventNode().addListener(AsyncPlayerConfigurationEvent.class, event -> {
|
||||
event.setSpawningInstance(instance);
|
||||
event.getPlayer().setRespawnPoint(pos);
|
||||
});
|
||||
|
||||
return process.connection().createPlayer(player, true)
|
||||
.thenApply(unused -> {
|
||||
process.connection().updateWaitingPlayers();
|
||||
return player;
|
||||
});
|
||||
// Force the player through the entirety of the login process manually
|
||||
playerConnection.setServerState(ConnectionState.CONFIGURATION);
|
||||
process.connection().doConfiguration(player, true);
|
||||
process.connection().transitionConfigToPlay(player);
|
||||
playerConnection.setServerState(ConnectionState.PLAY);
|
||||
process.connection().updateWaitingPlayers();
|
||||
return CompletableFuture.completedFuture(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,7 +69,7 @@ final class TestConnectionImpl implements TestConnection {
|
||||
}
|
||||
|
||||
private ServerPacket extractPacket(final SendablePacket packet) {
|
||||
if (!(packet instanceof ServerPacket serverPacket)) return SendablePacket.extractServerPacket(getConnectionState(), packet);
|
||||
if (!(packet instanceof ServerPacket serverPacket)) return SendablePacket.extractServerPacket(getServerState(), packet);
|
||||
|
||||
final Player player = getPlayer();
|
||||
if (player == null) return serverPacket;
|
||||
|
Loading…
Reference in New Issue
Block a user