mirror of https://github.com/Minestom/Minestom.git
chore: add PlayerAnvilInputEvent, other minor tweaks from self review
This commit is contained in:
parent
54e30c2d67
commit
0c35fdfd7e
|
@ -23,6 +23,7 @@ import net.minestom.server.network.packet.server.play.DeclareRecipesPacket;
|
|||
import net.minestom.server.ping.ResponseData;
|
||||
import net.minestom.server.recipe.RecipeCategory;
|
||||
import net.minestom.server.recipe.ShapedRecipe;
|
||||
import net.minestom.server.recipe.ShapelessRecipe;
|
||||
import net.minestom.server.utils.identity.NamedAndIdentified;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -33,11 +34,6 @@ import java.util.List;
|
|||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
Class.forName(ItemComponent.class.getName());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
System.setProperty("minestom.experiment.pose-updates", "true");
|
||||
|
||||
MinecraftServer.setCompressionThreshold(0);
|
||||
|
@ -141,22 +137,22 @@ public class Main {
|
|||
}
|
||||
};
|
||||
MinecraftServer.getRecipeManager().addRecipe(ironBlockRecipe);
|
||||
// var recipe = new ShapelessRecipe(
|
||||
// "minestom:test2", "abc",
|
||||
// RecipeCategory.Crafting.MISC,
|
||||
// List.of(
|
||||
// new DeclareRecipesPacket.Ingredient(List.of(ItemStack.AIR))
|
||||
// ),
|
||||
// ItemStack.builder(Material.GOLD_BLOCK)
|
||||
// .set(ItemComponent.CUSTOM_NAME, Component.text("abc"))
|
||||
// .build()
|
||||
// ) {
|
||||
// @Override
|
||||
// public boolean shouldShow(@NotNull Player player) {
|
||||
// return true;
|
||||
// }
|
||||
// };
|
||||
// MinecraftServer.getRecipeManager().addRecipe(recipe);
|
||||
var recipe = new ShapelessRecipe(
|
||||
"minestom:test2", "abc",
|
||||
RecipeCategory.Crafting.MISC,
|
||||
List.of(
|
||||
new DeclareRecipesPacket.Ingredient(List.of(ItemStack.of(Material.DIRT)))
|
||||
),
|
||||
ItemStack.builder(Material.GOLD_BLOCK)
|
||||
.set(ItemComponent.CUSTOM_NAME, Component.text("abc"))
|
||||
.build()
|
||||
) {
|
||||
@Override
|
||||
public boolean shouldShow(@NotNull Player player) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
MinecraftServer.getRecipeManager().addRecipe(recipe);
|
||||
|
||||
PlayerInit.init();
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import net.minestom.server.advancements.notifications.Notification;
|
|||
import net.minestom.server.advancements.notifications.NotificationCenter;
|
||||
import net.minestom.server.adventure.MinestomAdventure;
|
||||
import net.minestom.server.adventure.audience.Audiences;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.Entity;
|
||||
|
@ -39,18 +38,11 @@ import net.minestom.server.item.component.ItemBlockState;
|
|||
import net.minestom.server.item.component.PotionContents;
|
||||
import net.minestom.server.monitoring.BenchmarkManager;
|
||||
import net.minestom.server.monitoring.TickMonitor;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.play.ExplosionPacket;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.particle.data.BlockParticleData;
|
||||
import net.minestom.server.potion.CustomPotionEffect;
|
||||
import net.minestom.server.potion.PotionEffect;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
@ -98,8 +90,6 @@ public class PlayerInit {
|
|||
itemEntity.setInstance(player.getInstance(), playerPos.withY(y -> y + 1.5));
|
||||
Vec velocity = playerPos.direction().mul(6);
|
||||
itemEntity.setVelocity(velocity);
|
||||
|
||||
player.sendPacket(makeExplosion(playerPos, velocity));
|
||||
})
|
||||
.addListener(PlayerDisconnectEvent.class, event -> System.out.println("DISCONNECTION " + event.getPlayer().getUsername()))
|
||||
.addListener(AsyncPlayerConfigurationEvent.class, event -> {
|
||||
|
@ -188,20 +178,6 @@ public class PlayerInit {
|
|||
event.getInstance().setBlock(event.getBlockPosition(), block);
|
||||
});
|
||||
|
||||
private static final byte[] AIR_BLOCK_PARTICLE = NetworkBuffer.makeArray(new BlockParticleData(Block.AIR)::write);
|
||||
|
||||
private static @NotNull ExplosionPacket makeExplosion(@NotNull Point position, @NotNull Vec motion) {
|
||||
return new ExplosionPacket(
|
||||
position.x(), position.y(), position.z(),
|
||||
0, new byte[0],
|
||||
(float) motion.x(), (float) motion.y(), (float) motion.z(),
|
||||
ExplosionPacket.BlockInteraction.KEEP,
|
||||
Particle.BLOCK.id(), AIR_BLOCK_PARTICLE,
|
||||
Particle.BLOCK.id(), AIR_BLOCK_PARTICLE,
|
||||
SoundEvent.of(NamespaceID.from("not.a.real.sound"), 0f)
|
||||
);
|
||||
}
|
||||
|
||||
static {
|
||||
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
|
||||
|
||||
|
@ -250,8 +226,7 @@ public class PlayerInit {
|
|||
|
||||
BenchmarkManager benchmarkManager = MinecraftServer.getBenchmarkManager();
|
||||
MinecraftServer.getSchedulerManager().buildTask(() -> {
|
||||
if (LAST_TICK.get() == null) return;
|
||||
if (MinecraftServer.getConnectionManager().getOnlinePlayerCount() == 0)
|
||||
if (LAST_TICK.get() == null || MinecraftServer.getConnectionManager().getOnlinePlayerCount() == 0)
|
||||
return;
|
||||
|
||||
long ramUsage = benchmarkManager.getUsedMemory();
|
||||
|
|
|
@ -44,9 +44,9 @@ public final class MinecraftServer {
|
|||
|
||||
public static final ComponentLogger LOGGER = ComponentLogger.logger(MinecraftServer.class);
|
||||
|
||||
public static final String VERSION_NAME = "1.20.5";
|
||||
public static final String VERSION_NAME = "1.20.6";
|
||||
public static final int PROTOCOL_VERSION = 766;
|
||||
public static final int DATA_VERSION = 3837;
|
||||
public static final int DATA_VERSION = 3839;
|
||||
|
||||
// Threads
|
||||
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";
|
||||
|
|
|
@ -298,7 +298,7 @@ final class BlockCollision {
|
|||
// don't fall out of if statement, we could end up redundantly grabbing a block, and we only need to
|
||||
// collision check against the current shape since the below shape isn't tall
|
||||
if (belowShape.relativeEnd().y() > 1) {
|
||||
// we should always check both shapes, so no short-circuit here, to handle properties where the bounding box
|
||||
// we should always check both shapes, so no short-circuit here, to handle cases where the bounding box
|
||||
// hits the current solid but misses the tall solid
|
||||
return belowShape.intersectBoxSwept(entityPosition, entityVelocity, belowPos, boundingBox, finalResult) |
|
||||
(currentCollidable && currentShape.intersectBoxSwept(entityPosition, entityVelocity, currentPos, boundingBox, finalResult));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.minestom.server.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.minestom.server.item.ItemComponent;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.collection.ObjectArray;
|
||||
|
@ -18,10 +19,10 @@ record DataComponentImpl<T>(
|
|||
@Nullable NetworkBuffer.Type<T> network,
|
||||
@Nullable BinaryTagSerializer<T> nbt
|
||||
) implements DataComponent<T> {
|
||||
|
||||
static final Map<String, DataComponent<?>> NAMESPACES = new HashMap<>(32);
|
||||
static final ObjectArray<DataComponent<?>> IDS = ObjectArray.singleThread(32);
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull T read(@NotNull BinaryTag tag) {
|
||||
Check.notNull(nbt, "{0} cannot be deserialized from NBT", this);
|
||||
|
@ -50,4 +51,14 @@ record DataComponentImpl<T>(
|
|||
public String toString() {
|
||||
return name();
|
||||
}
|
||||
|
||||
static {
|
||||
try {
|
||||
// Force init of item component for the weird edge case of tests which reference a component by
|
||||
// loading it (with fromNamespaceId) before referencing a component by name
|
||||
Class.forName(ItemComponent.class.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1096,14 +1096,14 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets and refresh client food saturationModifier.
|
||||
* Sets and refresh client food saturation.
|
||||
*
|
||||
* @param foodSaturation the food saturationModifier
|
||||
* @param foodSaturation the food saturation
|
||||
* @throws IllegalArgumentException if {@code foodSaturation} is not between 0 and 20
|
||||
*/
|
||||
public void setFoodSaturation(float foodSaturation) {
|
||||
Check.argCondition(!MathUtils.isBetween(foodSaturation, 0, 20),
|
||||
"Food saturationModifier has to be between 0 and 20");
|
||||
"Food saturation has to be between 0 and 20");
|
||||
this.foodSaturation = foodSaturation;
|
||||
sendPacket(new UpdateHealthPacket(getHealth(), food, foodSaturation));
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.minestom.server.event.player;
|
|||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.trait.PlayerEvent;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.network.packet.server.configuration.ResetChatPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -20,6 +21,7 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent {
|
|||
private final boolean isFirstConfig;
|
||||
|
||||
private boolean hardcore;
|
||||
private boolean clearChat;
|
||||
private boolean sendRegistryData;
|
||||
private Instance spawningInstance;
|
||||
|
||||
|
@ -28,6 +30,7 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent {
|
|||
this.isFirstConfig = isFirstConfig;
|
||||
|
||||
this.hardcore = false;
|
||||
this.clearChat = false;
|
||||
this.sendRegistryData = isFirstConfig;
|
||||
this.spawningInstance = null;
|
||||
}
|
||||
|
@ -52,6 +55,29 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent {
|
|||
this.hardcore = hardcore;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, the player's chat will be cleared when exiting the configuration state, otherwise
|
||||
* it will be preserved. The default is not to clear the chat.
|
||||
*
|
||||
* @return true if the chat will be cleared, false otherwise
|
||||
*
|
||||
* @see ResetChatPacket
|
||||
*/
|
||||
public boolean willClearChat() {
|
||||
return clearChat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the player's chat will be cleared when exiting the configuration state.
|
||||
*
|
||||
* @param clearChat true to clear the chat, false otherwise
|
||||
*
|
||||
* @see ResetChatPacket
|
||||
*/
|
||||
public void setClearChat(boolean clearChat) {
|
||||
this.clearChat = clearChat;
|
||||
}
|
||||
|
||||
public boolean willSendRegistryData() {
|
||||
return sendRegistryData;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package net.minestom.server.event.player;
|
||||
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
||||
import net.minestom.server.network.packet.client.play.ClientNameItemPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Called every time a {@link Player} types a letter in an anvil GUI.
|
||||
*
|
||||
* @see ClientNameItemPacket
|
||||
*/
|
||||
public class PlayerAnvilInputEvent implements PlayerInstanceEvent {
|
||||
|
||||
private final Player player;
|
||||
private final String input;
|
||||
|
||||
public PlayerAnvilInputEvent(@NotNull Player player, @NotNull String input) {
|
||||
this.player = player;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public @NotNull String getInput() {
|
||||
return input;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package net.minestom.server.instance;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.LongArrayBinaryTag;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.ServerFlag;
|
||||
import net.minestom.server.collision.Shape;
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
package net.minestom.server.item.attribute;
|
||||
|
||||
import net.minestom.server.entity.EquipmentSlot;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public enum AttributeSlot {
|
||||
ANY,
|
||||
MAINHAND,
|
||||
OFFHAND,
|
||||
FEET,
|
||||
LEGS,
|
||||
CHEST,
|
||||
HEAD,
|
||||
ARMOR,
|
||||
BODY,
|
||||
ANY(EquipmentSlot.values()),
|
||||
MAINHAND(EquipmentSlot.MAIN_HAND),
|
||||
OFFHAND(EquipmentSlot.OFF_HAND),
|
||||
FEET(EquipmentSlot.BOOTS),
|
||||
LEGS(EquipmentSlot.LEGGINGS),
|
||||
CHEST(EquipmentSlot.CHESTPLATE),
|
||||
HEAD(EquipmentSlot.HELMET),
|
||||
ARMOR(EquipmentSlot.CHESTPLATE, EquipmentSlot.LEGGINGS, EquipmentSlot.BOOTS, EquipmentSlot.HELMET),
|
||||
BODY(EquipmentSlot.CHESTPLATE, EquipmentSlot.LEGGINGS);
|
||||
|
||||
private final List<EquipmentSlot> equipmentSlots;
|
||||
|
||||
AttributeSlot(@NotNull EquipmentSlot... equipmentSlots) {
|
||||
this.equipmentSlots = List.of(equipmentSlots);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (potentially multiple) equipment slots associated with this attribute slot.
|
||||
*/
|
||||
public @NotNull List<EquipmentSlot> equipmentSlots() {
|
||||
return this.equipmentSlots;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,12 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
public record ItemAttribute(@NotNull UUID uuid,
|
||||
@NotNull String name,
|
||||
@NotNull Attribute attribute,
|
||||
@NotNull AttributeOperation operation, double amount,
|
||||
@NotNull AttributeSlot slot) {
|
||||
public record ItemAttribute(
|
||||
@NotNull UUID uuid,
|
||||
@NotNull String name,
|
||||
@NotNull Attribute attribute,
|
||||
@NotNull AttributeOperation operation,
|
||||
double amount,
|
||||
@NotNull AttributeSlot slot
|
||||
) {
|
||||
}
|
||||
|
|
|
@ -83,4 +83,8 @@ public record EnchantmentList(@NotNull Map<Enchantment, Integer> enchantments, b
|
|||
newEnchantments.put(enchantment, level);
|
||||
return new EnchantmentList(newEnchantments, showInTooltip);
|
||||
}
|
||||
|
||||
public @NotNull EnchantmentList withTooltip(boolean showInTooltip) {
|
||||
return new EnchantmentList(enchantments, showInTooltip);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package net.minestom.server.listener;
|
||||
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.EventDispatcher;
|
||||
import net.minestom.server.event.player.PlayerAnvilInputEvent;
|
||||
import net.minestom.server.inventory.ContainerInventory;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.network.packet.client.play.ClientNameItemPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class AnvilListener {
|
||||
|
||||
public static void nameItemListener(@NotNull ClientNameItemPacket packet, @NotNull Player player) {
|
||||
if (!(player.getOpenInventory() instanceof ContainerInventory openInventory))
|
||||
return;
|
||||
if (openInventory.getInventoryType() != InventoryType.ANVIL)
|
||||
return;
|
||||
|
||||
EventDispatcher.call(new PlayerAnvilInputEvent(player, packet.itemName()));
|
||||
}
|
||||
|
||||
private AnvilListener() {
|
||||
}
|
||||
|
||||
}
|
|
@ -149,7 +149,7 @@ public class BlockPlacementListener {
|
|||
// If a player is trying to place a block on themselves, the client will send a block change but will not set the block on the client
|
||||
// For this reason, the block doesn't need to be updated for the client
|
||||
|
||||
// Client also doesn't predict placement of blocks on entities, but we need to refresh for properties where bounding boxes on the server don't match the client
|
||||
// Client also doesn't predict placement of blocks on entities, but we need to refresh for cases where bounding boxes on the server don't match the client
|
||||
if (collisionEntity != player)
|
||||
refresh(player, chunk);
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ public final class PacketListenerManager {
|
|||
setPlayListener(ClientChunkBatchReceivedPacket.class, ChunkBatchListener::batchReceivedListener);
|
||||
setPlayListener(ClientPingRequestPacket.class, PlayPingListener::requestListener);
|
||||
setListener(ConnectionState.PLAY, ClientCookieResponsePacket.class, CookieListener::handleCookieResponse);
|
||||
setPlayListener(ClientNameItemPacket.class, AnvilListener::nameItemListener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,10 +13,12 @@ import net.minestom.server.instance.Instance;
|
|||
import net.minestom.server.listener.preplay.LoginListener;
|
||||
import net.minestom.server.message.Messenger;
|
||||
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
|
||||
import net.minestom.server.network.packet.server.CachedPacket;
|
||||
import net.minestom.server.network.packet.server.common.KeepAlivePacket;
|
||||
import net.minestom.server.network.packet.server.common.PluginMessagePacket;
|
||||
import net.minestom.server.network.packet.server.common.TagsPacket;
|
||||
import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket;
|
||||
import net.minestom.server.network.packet.server.configuration.ResetChatPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
|
||||
import net.minestom.server.network.packet.server.play.StartConfigurationPacket;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
|
@ -63,6 +65,8 @@ public final class ConnectionManager {
|
|||
private final Set<Player> unmodifiableConfigurationPlayers = Collections.unmodifiableSet(configurationPlayers);
|
||||
private final Set<Player> unmodifiablePlayPlayers = Collections.unmodifiableSet(playPlayers);
|
||||
|
||||
private final CachedPacket resetChatPacket = new CachedPacket(new ResetChatPacket());
|
||||
|
||||
|
||||
// The uuid provider once a player login
|
||||
private volatile UuidProvider uuidProvider = (playerConnection, username) -> UUID.randomUUID();
|
||||
|
@ -276,6 +280,10 @@ public final class ConnectionManager {
|
|||
final Instance spawningInstance = event.getSpawningInstance();
|
||||
Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent");
|
||||
|
||||
if (event.willClearChat()) {
|
||||
player.sendPacket(resetChatPacket);
|
||||
}
|
||||
|
||||
// Registry data (if it should be sent)
|
||||
if (event.willSendRegistryData()) {
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ public record ClientHandshakePacket(int protocolVersion, @NotNull String serverA
|
|||
|
||||
public ClientHandshakePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), reader.read(STRING),
|
||||
reader.read(UNSIGNED_SHORT), Intent.fromId(reader.read(VAR_INT)));
|
||||
reader.read(UNSIGNED_SHORT),
|
||||
// Not a readEnum call because the indices are not 0-based
|
||||
Intent.fromId(reader.read(VAR_INT)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,6 +32,7 @@ public record ClientHandshakePacket(int protocolVersion, @NotNull String serverA
|
|||
}
|
||||
writer.write(STRING, serverAddress);
|
||||
writer.write(UNSIGNED_SHORT, serverPort);
|
||||
// Not a writeEnum call because the indices are not 0-based
|
||||
writer.write(VAR_INT, intent.id());
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ public interface BinaryTagSerializer<T> {
|
|||
|
||||
@Override
|
||||
public @NotNull Integer read(@NotNull BinaryTag tag) {
|
||||
return tag instanceof IntBinaryTag intBinaryTag ? intBinaryTag.value() : 0;
|
||||
return tag instanceof NumberBinaryTag numberTag ? numberTag.intValue() : 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue