mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-23 00:21:26 +01:00
Merge branch 'master' into new-position-api
This commit is contained in:
commit
f8a9664fd9
17
build.gradle
17
build.gradle
@ -36,9 +36,6 @@ allprojects {
|
|||||||
name 'sponge'
|
name 'sponge'
|
||||||
url 'https://repo.spongepowered.org/maven'
|
url 'https://repo.spongepowered.org/maven'
|
||||||
}
|
}
|
||||||
maven {
|
|
||||||
url "https://repo.velocitypowered.com/snapshots/"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
javadoc {
|
javadoc {
|
||||||
options {
|
options {
|
||||||
@ -111,11 +108,10 @@ dependencies {
|
|||||||
testCompileOnly "org.mockito:mockito-core:2.28.2"
|
testCompileOnly "org.mockito:mockito-core:2.28.2"
|
||||||
|
|
||||||
// Netty
|
// Netty
|
||||||
api 'io.netty:netty-handler:4.1.63.Final'
|
api 'io.netty:netty-handler:4.1.65.Final'
|
||||||
api 'io.netty:netty-codec:4.1.63.Final'
|
api 'io.netty:netty-codec:4.1.65.Final'
|
||||||
api 'io.netty:netty-transport-native-epoll:4.1.63.Final:linux-x86_64'
|
api 'io.netty:netty-transport-native-epoll:4.1.65.Final:linux-x86_64'
|
||||||
api 'io.netty:netty-transport-native-kqueue:4.1.63.Final:osx-x86_64'
|
api 'io.netty:netty-transport-native-kqueue:4.1.65.Final:osx-x86_64'
|
||||||
api 'io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.5.Final:linux-x86_64'
|
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
|
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
|
||||||
api 'it.unimi.dsi:fastutil:8.5.4'
|
api 'it.unimi.dsi:fastutil:8.5.4'
|
||||||
@ -142,6 +138,8 @@ dependencies {
|
|||||||
// https://search.maven.org/artifact/org.fusesource.jansi/jansi/2.3.2/jar
|
// https://search.maven.org/artifact/org.fusesource.jansi/jansi/2.3.2/jar
|
||||||
implementation 'org.fusesource.jansi:jansi:2.3.2'
|
implementation 'org.fusesource.jansi:jansi:2.3.2'
|
||||||
|
|
||||||
|
implementation 'com.github.ben-manes.caffeine:caffeine:3.0.2'
|
||||||
|
|
||||||
// Guava 21.0+ required for Mixin
|
// Guava 21.0+ required for Mixin
|
||||||
api 'com.google.guava:guava:30.1-jre'
|
api 'com.google.guava:guava:30.1-jre'
|
||||||
|
|
||||||
@ -153,9 +151,6 @@ dependencies {
|
|||||||
api "org.ow2.asm:asm-commons:${asmVersion}"
|
api "org.ow2.asm:asm-commons:${asmVersion}"
|
||||||
api "org.spongepowered:mixin:${mixinVersion}"
|
api "org.spongepowered:mixin:${mixinVersion}"
|
||||||
|
|
||||||
// Compression
|
|
||||||
implementation "com.velocitypowered:velocity-native:1.1.0-SNAPSHOT"
|
|
||||||
|
|
||||||
// Path finding
|
// Path finding
|
||||||
api 'com.github.MadMartian:hydrazine-path-finding:1.6.0'
|
api 'com.github.MadMartian:hydrazine-path-finding:1.6.0'
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server;
|
package net.minestom.server;
|
||||||
|
|
||||||
import com.google.common.collect.Queues;
|
|
||||||
import net.minestom.server.acquirable.Acquirable;
|
import net.minestom.server.acquirable.Acquirable;
|
||||||
import net.minestom.server.instance.Chunk;
|
import net.minestom.server.instance.Chunk;
|
||||||
import net.minestom.server.instance.Instance;
|
import net.minestom.server.instance.Instance;
|
||||||
@ -34,8 +33,8 @@ public final class UpdateManager {
|
|||||||
// TODO make configurable
|
// TODO make configurable
|
||||||
private ThreadProvider threadProvider = new SingleThreadProvider();
|
private ThreadProvider threadProvider = new SingleThreadProvider();
|
||||||
|
|
||||||
private final Queue<LongConsumer> tickStartCallbacks = Queues.newConcurrentLinkedQueue();
|
private final Queue<LongConsumer> tickStartCallbacks = new ConcurrentLinkedQueue<>();
|
||||||
private final Queue<LongConsumer> tickEndCallbacks = Queues.newConcurrentLinkedQueue();
|
private final Queue<LongConsumer> tickEndCallbacks = new ConcurrentLinkedQueue<>();
|
||||||
private final List<Consumer<TickMonitor>> tickMonitors = new CopyOnWriteArrayList<>();
|
private final List<Consumer<TickMonitor>> tickMonitors = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.acquirable;
|
package net.minestom.server.acquirable;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import net.minestom.server.entity.Entity;
|
import net.minestom.server.entity.Entity;
|
||||||
import net.minestom.server.thread.ThreadProvider;
|
import net.minestom.server.thread.ThreadProvider;
|
||||||
import net.minestom.server.thread.TickThread;
|
import net.minestom.server.thread.TickThread;
|
||||||
@ -14,7 +13,7 @@ import java.util.Optional;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public interface Acquirable<T> {
|
public interface Acquirable<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package net.minestom.server.acquirable;
|
package net.minestom.server.acquirable;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import net.minestom.server.thread.TickThread;
|
import net.minestom.server.thread.TickThread;
|
||||||
import net.minestom.server.utils.async.AsyncUtils;
|
import net.minestom.server.utils.async.AsyncUtils;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public class AcquirableCollection<E> implements Collection<Acquirable<E>> {
|
public class AcquirableCollection<E> implements Collection<Acquirable<E>> {
|
||||||
|
|
||||||
private final Collection<Acquirable<E>> acquirableCollection;
|
private final Collection<Acquirable<E>> acquirableCollection;
|
||||||
|
@ -14,6 +14,7 @@ import net.minestom.server.adventure.AdventurePacketConvertor;
|
|||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.message.ChatPosition;
|
import net.minestom.server.message.ChatPosition;
|
||||||
import net.minestom.server.message.Messenger;
|
import net.minestom.server.message.Messenger;
|
||||||
|
import net.minestom.server.network.packet.server.ServerPacket;
|
||||||
import net.minestom.server.network.packet.server.play.*;
|
import net.minestom.server.network.packet.server.play.*;
|
||||||
import net.minestom.server.utils.PacketUtils;
|
import net.minestom.server.utils.PacketUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -44,6 +45,14 @@ public interface PacketGroupingAudience extends ForwardingAudience {
|
|||||||
*/
|
*/
|
||||||
@NotNull Collection<Player> getPlayers();
|
@NotNull Collection<Player> getPlayers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a ServerPacket to all players of this audience
|
||||||
|
* @param packet the packet to broadcast
|
||||||
|
*/
|
||||||
|
default void sendGroupedPacket(ServerPacket packet) {
|
||||||
|
PacketUtils.sendGroupedPacket(this.getPlayers(), packet);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
|
default void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
|
||||||
Messenger.sendMessage(this.getPlayers(), message, ChatPosition.fromMessageType(type), source.uuid());
|
Messenger.sendMessage(this.getPlayers(), message, ChatPosition.fromMessageType(type), source.uuid());
|
||||||
@ -51,28 +60,28 @@ public interface PacketGroupingAudience extends ForwardingAudience {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void sendActionBar(@NotNull Component message) {
|
default void sendActionBar(@NotNull Component message) {
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new ActionBarPacket(message));
|
sendGroupedPacket(new ActionBarPacket(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void sendPlayerListHeaderAndFooter(@NotNull Component header, @NotNull Component footer) {
|
default void sendPlayerListHeaderAndFooter(@NotNull Component header, @NotNull Component footer) {
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new PlayerListHeaderAndFooterPacket(header, footer));
|
sendGroupedPacket(new PlayerListHeaderAndFooterPacket(header, footer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void showTitle(@NotNull Title title) {
|
default void showTitle(@NotNull Title title) {
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new SetTitleTextPacket(title.title()));
|
sendGroupedPacket(new SetTitleTextPacket(title.title()));
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new SetTitleSubTitlePacket(title.subtitle()));
|
sendGroupedPacket(new SetTitleSubTitlePacket(title.subtitle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void clearTitle() {
|
default void clearTitle() {
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new ClearTitlesPacket());
|
sendGroupedPacket(new ClearTitlesPacket());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void resetTitle() {
|
default void resetTitle() {
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new ClearTitlesPacket(true));
|
sendGroupedPacket(new ClearTitlesPacket(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,13 +96,13 @@ public interface PacketGroupingAudience extends ForwardingAudience {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void playSound(@NotNull Sound sound, double x, double y, double z) {
|
default void playSound(@NotNull Sound sound, double x, double y, double z) {
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), AdventurePacketConvertor.createSoundPacket(sound, x, y, z));
|
sendGroupedPacket(AdventurePacketConvertor.createSoundPacket(sound, x, y, z));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void playSound(@NotNull Sound sound, Sound.@NotNull Emitter emitter) {
|
default void playSound(@NotNull Sound sound, Sound.@NotNull Emitter emitter) {
|
||||||
if (emitter != Sound.Emitter.self()) {
|
if (emitter != Sound.Emitter.self()) {
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), AdventurePacketConvertor.createSoundPacket(sound, emitter));
|
sendGroupedPacket(AdventurePacketConvertor.createSoundPacket(sound, emitter));
|
||||||
} else {
|
} else {
|
||||||
// if we're playing on self, we need to delegate to each audience member
|
// if we're playing on self, we need to delegate to each audience member
|
||||||
for (Audience audience : this.audiences()) {
|
for (Audience audience : this.audiences()) {
|
||||||
@ -104,7 +113,7 @@ public interface PacketGroupingAudience extends ForwardingAudience {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void stopSound(@NotNull SoundStop stop) {
|
default void stopSound(@NotNull SoundStop stop) {
|
||||||
PacketUtils.sendGroupedPacket(this.getPlayers(), AdventurePacketConvertor.createSoundStopPacket(stop));
|
sendGroupedPacket(AdventurePacketConvertor.createSoundStopPacket(stop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.minestom.server.attribute;
|
package net.minestom.server.attribute;
|
||||||
|
|
||||||
import io.netty.util.internal.ThreadLocalRandom;
|
|
||||||
import net.minestom.server.utils.UniqueIdUtils;
|
import net.minestom.server.utils.UniqueIdUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represent an attribute modifier.
|
* Represent an attribute modifier.
|
||||||
|
@ -5,6 +5,7 @@ import net.kyori.adventure.text.Component;
|
|||||||
import net.minestom.server.chat.JsonMessage;
|
import net.minestom.server.chat.JsonMessage;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.permission.PermissionHandler;
|
import net.minestom.server.permission.PermissionHandler;
|
||||||
|
import net.minestom.server.tag.TagHandler;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,7 +13,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
* <p>
|
* <p>
|
||||||
* Main implementations are {@link Player} and {@link ConsoleSender}.
|
* Main implementations are {@link Player} and {@link ConsoleSender}.
|
||||||
*/
|
*/
|
||||||
public interface CommandSender extends PermissionHandler, Audience {
|
public interface CommandSender extends PermissionHandler, Audience, TagHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a raw string message.
|
* Sends a raw string message.
|
||||||
@ -28,7 +29,7 @@ public interface CommandSender extends PermissionHandler, Audience {
|
|||||||
*
|
*
|
||||||
* @param messages the messages to send
|
* @param messages the messages to send
|
||||||
*/
|
*/
|
||||||
default void sendMessage(@NotNull String @NotNull[] messages) {
|
default void sendMessage(@NotNull String @NotNull [] messages) {
|
||||||
for (String message : messages) {
|
for (String message : messages) {
|
||||||
sendMessage(message);
|
sendMessage(message);
|
||||||
}
|
}
|
||||||
@ -39,9 +40,8 @@ public interface CommandSender extends PermissionHandler, Audience {
|
|||||||
* If this is not a {@link Player}, only the content of the message will be sent as a string.
|
* If this is not a {@link Player}, only the content of the message will be sent as a string.
|
||||||
*
|
*
|
||||||
* @param text The {@link JsonMessage} to send.
|
* @param text The {@link JsonMessage} to send.
|
||||||
*
|
|
||||||
* @deprecated Use {@link #sendMessage(Component)}
|
* @deprecated Use {@link #sendMessage(Component)}
|
||||||
* */
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
default void sendMessage(@NotNull JsonMessage text) {
|
default void sendMessage(@NotNull JsonMessage text) {
|
||||||
this.sendMessage(text.asComponent());
|
this.sendMessage(text.asComponent());
|
||||||
|
@ -3,9 +3,12 @@ package net.minestom.server.command;
|
|||||||
import net.kyori.adventure.audience.MessageType;
|
import net.kyori.adventure.audience.MessageType;
|
||||||
import net.kyori.adventure.identity.Identity;
|
import net.kyori.adventure.identity.Identity;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
import net.minestom.server.permission.Permission;
|
import net.minestom.server.permission.Permission;
|
||||||
|
import net.minestom.server.tag.Tag;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -16,10 +19,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
* Represents the console when sending a command to the server.
|
* Represents the console when sending a command to the server.
|
||||||
*/
|
*/
|
||||||
public class ConsoleSender implements CommandSender {
|
public class ConsoleSender implements CommandSender {
|
||||||
private static final PlainComponentSerializer PLAIN_SERIALIZER = PlainComponentSerializer.plain();
|
private static final PlainTextComponentSerializer PLAIN_SERIALIZER = PlainTextComponentSerializer.plainText();
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleSender.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleSender.class);
|
||||||
|
|
||||||
private final Set<Permission> permissions = new CopyOnWriteArraySet<>();
|
private final Set<Permission> permissions = new CopyOnWriteArraySet<>();
|
||||||
|
private final NBTCompound nbtCompound = new NBTCompound();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(@NotNull String message) {
|
public void sendMessage(@NotNull String message) {
|
||||||
@ -47,4 +51,14 @@ public class ConsoleSender implements CommandSender {
|
|||||||
public ConsoleSender asConsole() {
|
public ConsoleSender asConsole() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||||
|
return tag.read(nbtCompound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
|
tag.write(nbtCompound, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,10 @@ package net.minestom.server.command;
|
|||||||
import net.minestom.server.command.builder.CommandContext;
|
import net.minestom.server.command.builder.CommandContext;
|
||||||
import net.kyori.adventure.audience.Audience;
|
import net.kyori.adventure.audience.Audience;
|
||||||
import net.minestom.server.permission.Permission;
|
import net.minestom.server.permission.Permission;
|
||||||
|
import net.minestom.server.tag.Tag;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -19,10 +22,21 @@ import java.util.Set;
|
|||||||
public class ServerSender implements CommandSender {
|
public class ServerSender implements CommandSender {
|
||||||
|
|
||||||
private final Set<Permission> permissions = Collections.unmodifiableSet(new HashSet<>());
|
private final Set<Permission> permissions = Collections.unmodifiableSet(new HashSet<>());
|
||||||
|
private final NBTCompound nbtCompound = new NBTCompound();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Set<Permission> getAllPermissions() {
|
public Set<Permission> getAllPermissions() {
|
||||||
return permissions;
|
return permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||||
|
return tag.read(nbtCompound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
|
tag.write(nbtCompound, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.command.builder;
|
package net.minestom.server.command.builder;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import net.minestom.server.command.CommandSender;
|
import net.minestom.server.command.CommandSender;
|
||||||
@ -10,6 +9,7 @@ import net.minestom.server.command.builder.arguments.ArgumentType;
|
|||||||
import net.minestom.server.command.builder.arguments.ArgumentWord;
|
import net.minestom.server.command.builder.arguments.ArgumentWord;
|
||||||
import net.minestom.server.command.builder.condition.CommandCondition;
|
import net.minestom.server.command.builder.condition.CommandCondition;
|
||||||
import net.minestom.server.utils.StringUtils;
|
import net.minestom.server.utils.StringUtils;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -221,7 +221,7 @@ public class Command {
|
|||||||
* @param format the syntax format
|
* @param format the syntax format
|
||||||
* @return the newly created {@link CommandSyntax syntaxes}.
|
* @return the newly created {@link CommandSyntax syntaxes}.
|
||||||
*/
|
*/
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public @NotNull Collection<CommandSyntax> addSyntax(@NotNull CommandExecutor executor, @NotNull String format) {
|
public @NotNull Collection<CommandSyntax> addSyntax(@NotNull CommandExecutor executor, @NotNull String format) {
|
||||||
return addSyntax(executor, ArgumentType.generate(format));
|
return addSyntax(executor, ArgumentType.generate(format));
|
||||||
}
|
}
|
||||||
@ -302,7 +302,7 @@ public class Command {
|
|||||||
public void globalListener(@NotNull CommandSender sender, @NotNull CommandContext context, @NotNull String command) {
|
public void globalListener(@NotNull CommandSender sender, @NotNull CommandContext context, @NotNull String command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public @NotNull Set<String> getSyntaxesStrings() {
|
public @NotNull Set<String> getSyntaxesStrings() {
|
||||||
Set<String> syntaxes = new HashSet<>();
|
Set<String> syntaxes = new HashSet<>();
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ public class Command {
|
|||||||
return syntaxes;
|
return syntaxes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public @NotNull String getSyntaxesTree() {
|
public @NotNull String getSyntaxesTree() {
|
||||||
Node commandNode = new Node();
|
Node commandNode = new Node();
|
||||||
commandNode.names.addAll(Arrays.asList(getNames()));
|
commandNode.names.addAll(Arrays.asList(getNames()));
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.minestom.server.command.builder;
|
package net.minestom.server.command.builder;
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
|
||||||
import net.minestom.server.command.CommandSender;
|
import net.minestom.server.command.CommandSender;
|
||||||
import net.minestom.server.command.builder.arguments.Argument;
|
import net.minestom.server.command.builder.arguments.Argument;
|
||||||
@ -25,7 +25,7 @@ public class CommandDispatcher {
|
|||||||
private final Map<String, Command> commandMap = new HashMap<>();
|
private final Map<String, Command> commandMap = new HashMap<>();
|
||||||
private final Set<Command> commands = new HashSet<>();
|
private final Set<Command> commands = new HashSet<>();
|
||||||
|
|
||||||
private final Cache<String, CommandResult> cache = CacheBuilder.newBuilder()
|
private final Cache<String, CommandResult> cache = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(30, TimeUnit.SECONDS)
|
.expireAfterWrite(30, TimeUnit.SECONDS)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.command.builder.arguments;
|
package net.minestom.server.command.builder.arguments;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import net.minestom.server.command.builder.ArgumentCallback;
|
import net.minestom.server.command.builder.ArgumentCallback;
|
||||||
import net.minestom.server.command.builder.Command;
|
import net.minestom.server.command.builder.Command;
|
||||||
import net.minestom.server.command.builder.CommandExecutor;
|
import net.minestom.server.command.builder.CommandExecutor;
|
||||||
@ -8,6 +7,7 @@ import net.minestom.server.command.builder.NodeMaker;
|
|||||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||||
import net.minestom.server.command.builder.suggestion.SuggestionCallback;
|
import net.minestom.server.command.builder.suggestion.SuggestionCallback;
|
||||||
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
|
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@ -210,8 +210,8 @@ public abstract class Argument<T> {
|
|||||||
/**
|
/**
|
||||||
* Gets the suggestion callback of the argument
|
* Gets the suggestion callback of the argument
|
||||||
*
|
*
|
||||||
* @see #setSuggestionCallback
|
|
||||||
* @return the suggestion callback of the argument, null if it doesn't exist
|
* @return the suggestion callback of the argument, null if it doesn't exist
|
||||||
|
* @see #setSuggestionCallback
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public SuggestionCallback getSuggestionCallback() {
|
public SuggestionCallback getSuggestionCallback() {
|
||||||
@ -247,7 +247,7 @@ public abstract class Argument<T> {
|
|||||||
* @param <O> The type of output expected.
|
* @param <O> The type of output expected.
|
||||||
* @return A new ArgumentMap that can get this complex object type.
|
* @return A new ArgumentMap that can get this complex object type.
|
||||||
*/
|
*/
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public <O> @NotNull ArgumentMap<T, O> map(@NotNull ArgumentMap.Mapper<T, O> mapper) {
|
public <O> @NotNull ArgumentMap<T, O> map(@NotNull ArgumentMap.Mapper<T, O> mapper) {
|
||||||
return new ArgumentMap<>(this, mapper);
|
return new ArgumentMap<>(this, mapper);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.command.builder.arguments;
|
package net.minestom.server.command.builder.arguments;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.command.builder.CommandDispatcher;
|
import net.minestom.server.command.builder.CommandDispatcher;
|
||||||
import net.minestom.server.command.builder.CommandResult;
|
import net.minestom.server.command.builder.CommandResult;
|
||||||
@ -8,6 +7,7 @@ import net.minestom.server.command.builder.NodeMaker;
|
|||||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||||
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
|
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
|
||||||
import net.minestom.server.utils.StringUtils;
|
import net.minestom.server.utils.StringUtils;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class ArgumentCommand extends Argument<CommandResult> {
|
public class ArgumentCommand extends Argument<CommandResult> {
|
||||||
@ -69,7 +69,7 @@ public class ArgumentCommand extends Argument<CommandResult> {
|
|||||||
return shortcut;
|
return shortcut;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public ArgumentCommand setShortcut(@NotNull String shortcut) {
|
public ArgumentCommand setShortcut(@NotNull String shortcut) {
|
||||||
this.shortcut = shortcut;
|
this.shortcut = shortcut;
|
||||||
return this;
|
return this;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.command.builder.arguments;
|
package net.minestom.server.command.builder.arguments;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import net.minestom.server.command.builder.arguments.minecraft.*;
|
import net.minestom.server.command.builder.arguments.minecraft.*;
|
||||||
import net.minestom.server.command.builder.arguments.minecraft.registry.*;
|
import net.minestom.server.command.builder.arguments.minecraft.registry.*;
|
||||||
import net.minestom.server.command.builder.arguments.number.ArgumentDouble;
|
import net.minestom.server.command.builder.arguments.number.ArgumentDouble;
|
||||||
@ -11,6 +10,7 @@ import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeBl
|
|||||||
import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVec2;
|
import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVec2;
|
||||||
import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVec3;
|
import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVec3;
|
||||||
import net.minestom.server.command.builder.parser.ArgumentParser;
|
import net.minestom.server.command.builder.parser.ArgumentParser;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,7 +248,7 @@ public class ArgumentType {
|
|||||||
* <p>
|
* <p>
|
||||||
* Note: this feature is in beta and is very likely to change depending on feedback.
|
* Note: this feature is in beta and is very likely to change depending on feedback.
|
||||||
*/
|
*/
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public static Argument<?>[] generate(@NotNull String format) {
|
public static Argument<?>[] generate(@NotNull String format) {
|
||||||
return ArgumentParser.generate(format);
|
return ArgumentParser.generate(format);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.command.builder.parser;
|
package net.minestom.server.command.builder.parser;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import net.minestom.server.command.builder.arguments.*;
|
import net.minestom.server.command.builder.arguments.*;
|
||||||
import net.minestom.server.command.builder.arguments.minecraft.*;
|
import net.minestom.server.command.builder.arguments.minecraft.*;
|
||||||
import net.minestom.server.command.builder.arguments.minecraft.registry.*;
|
import net.minestom.server.command.builder.arguments.minecraft.registry.*;
|
||||||
@ -12,6 +11,7 @@ import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVe
|
|||||||
import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVec3;
|
import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeVec3;
|
||||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||||
import net.minestom.server.utils.StringUtils;
|
import net.minestom.server.utils.StringUtils;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ public class ArgumentParser {
|
|||||||
ARGUMENT_FUNCTION_MAP.put("relativevec2", ArgumentRelativeVec2::new);
|
ARGUMENT_FUNCTION_MAP.put("relativevec2", ArgumentRelativeVec2::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public static @NotNull Argument<?>[] generate(@NotNull String format) {
|
public static @NotNull Argument<?>[] generate(@NotNull String format) {
|
||||||
List<Argument<?>> result = new ArrayList<>();
|
List<Argument<?>> result = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -6,7 +6,10 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
* Represents an element which can have a {@link Data} attached to it.
|
* Represents an element which can have a {@link Data} attached to it.
|
||||||
* <p>
|
* <p>
|
||||||
* The data will always be optional and can therefore be null.
|
* The data will always be optional and can therefore be null.
|
||||||
|
*
|
||||||
|
* @deprecated switch to the Tag API instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface DataContainer {
|
public interface DataContainer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,9 +19,10 @@ public interface DataContainer {
|
|||||||
* meaning that this will be null if no data has been defined.
|
* meaning that this will be null if no data has been defined.
|
||||||
*
|
*
|
||||||
* @return the {@link Data} of this container, can be null
|
* @return the {@link Data} of this container, can be null
|
||||||
|
* @deprecated use the tag API https://wiki.minestom.com/feature/tags
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Deprecated
|
||||||
Data getData();
|
@Nullable Data getData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link Data} of this container.
|
* Sets the {@link Data} of this container.
|
||||||
@ -27,7 +31,8 @@ public interface DataContainer {
|
|||||||
* on your use-case.
|
* on your use-case.
|
||||||
*
|
*
|
||||||
* @param data the new {@link Data} of this container, null to remove it
|
* @param data the new {@link Data} of this container, null to remove it
|
||||||
|
* @deprecated use the tag API https://wiki.minestom.com/feature/tags
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
void setData(@Nullable Data data);
|
void setData(@Nullable Data data);
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,5 @@
|
|||||||
package net.minestom.server.entity;
|
package net.minestom.server.entity;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import com.google.common.collect.Queues;
|
|
||||||
import net.kyori.adventure.sound.Sound;
|
import net.kyori.adventure.sound.Sound;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.event.HoverEvent;
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
@ -35,6 +33,8 @@ import net.minestom.server.permission.PermissionHandler;
|
|||||||
import net.minestom.server.potion.Potion;
|
import net.minestom.server.potion.Potion;
|
||||||
import net.minestom.server.potion.PotionEffect;
|
import net.minestom.server.potion.PotionEffect;
|
||||||
import net.minestom.server.potion.TimedPotion;
|
import net.minestom.server.potion.TimedPotion;
|
||||||
|
import net.minestom.server.tag.Tag;
|
||||||
|
import net.minestom.server.tag.TagHandler;
|
||||||
import net.minestom.server.thread.ThreadProvider;
|
import net.minestom.server.thread.ThreadProvider;
|
||||||
import net.minestom.server.utils.BlockPosition;
|
import net.minestom.server.utils.BlockPosition;
|
||||||
import net.minestom.server.utils.Position;
|
import net.minestom.server.utils.Position;
|
||||||
@ -51,9 +51,11 @@ import net.minestom.server.utils.validate.Check;
|
|||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@ -65,7 +67,7 @@ import java.util.function.UnaryOperator;
|
|||||||
* <p>
|
* <p>
|
||||||
* To create your own entity you probably want to extends {@link LivingEntity} or {@link EntityCreature} instead.
|
* To create your own entity you probably want to extends {@link LivingEntity} or {@link EntityCreature} instead.
|
||||||
*/
|
*/
|
||||||
public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, DataContainer, PermissionHandler, HoverEventSource<ShowEntity>, Sound.Emitter {
|
public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, DataContainer, TagHandler, PermissionHandler, HoverEventSource<ShowEntity>, Sound.Emitter {
|
||||||
|
|
||||||
private static final Map<Integer, Entity> ENTITY_BY_ID = new ConcurrentHashMap<>();
|
private static final Map<Integer, Entity> ENTITY_BY_ID = new ConcurrentHashMap<>();
|
||||||
private static final Map<UUID, Entity> ENTITY_BY_UUID = new ConcurrentHashMap<>();
|
private static final Map<UUID, Entity> ENTITY_BY_UUID = new ConcurrentHashMap<>();
|
||||||
@ -93,9 +95,18 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
protected Vector velocity = new Vector(); // Movement in block per second
|
protected Vector velocity = new Vector(); // Movement in block per second
|
||||||
protected boolean hasPhysics = true;
|
protected boolean hasPhysics = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of drag applied on the Y axle.
|
||||||
|
* <p>
|
||||||
|
* Unit: 1/tick
|
||||||
|
*/
|
||||||
protected double gravityDragPerTick;
|
protected double gravityDragPerTick;
|
||||||
|
/**
|
||||||
|
* Acceleration on the Y axle due to gravity
|
||||||
|
* <p>
|
||||||
|
* Unit: blocks/tick
|
||||||
|
*/
|
||||||
protected double gravityAcceleration;
|
protected double gravityAcceleration;
|
||||||
protected double gravityTerminalVelocity;
|
|
||||||
protected int gravityTickCount; // Number of tick where gravity tick was applied
|
protected int gravityTickCount; // Number of tick where gravity tick was applied
|
||||||
|
|
||||||
private boolean autoViewable;
|
private boolean autoViewable;
|
||||||
@ -103,6 +114,7 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
protected final Set<Player> viewers = ConcurrentHashMap.newKeySet();
|
protected final Set<Player> viewers = ConcurrentHashMap.newKeySet();
|
||||||
private final Set<Player> unmodifiableViewers = Collections.unmodifiableSet(viewers);
|
private final Set<Player> unmodifiableViewers = Collections.unmodifiableSet(viewers);
|
||||||
private Data data;
|
private Data data;
|
||||||
|
private final NBTCompound nbtCompound = new NBTCompound();
|
||||||
private final Set<Permission> permissions = new CopyOnWriteArraySet<>();
|
private final Set<Permission> permissions = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
protected UUID uuid;
|
protected UUID uuid;
|
||||||
@ -128,7 +140,7 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
private final List<TimedPotion> effects = new CopyOnWriteArrayList<>();
|
private final List<TimedPotion> effects = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
// list of scheduled tasks to be executed during the next entity tick
|
// list of scheduled tasks to be executed during the next entity tick
|
||||||
protected final Queue<Consumer<Entity>> nextTick = Queues.newConcurrentLinkedQueue();
|
protected final Queue<Consumer<Entity>> nextTick = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
// Tick related
|
// Tick related
|
||||||
private long ticks;
|
private long ticks;
|
||||||
@ -159,6 +171,8 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
Entity.ENTITY_BY_UUID.put(uuid, this);
|
Entity.ENTITY_BY_UUID.put(uuid, this);
|
||||||
|
|
||||||
this.eventNode = EventNode.value("entity-" + uuid, EventFilter.ENTITY, this::equals);
|
this.eventNode = EventNode.value("entity-" + uuid, EventFilter.ENTITY, this::equals);
|
||||||
|
|
||||||
|
initializeDefaultGravity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity(@NotNull EntityType entityType) {
|
public Entity(@NotNull EntityType entityType) {
|
||||||
@ -524,13 +538,11 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
Vector newVelocityOut = new Vector();
|
Vector newVelocityOut = new Vector();
|
||||||
|
|
||||||
// Gravity force
|
// Gravity force
|
||||||
final double gravityY = !hasNoGravity() ? Math.min(
|
final double gravityY = hasNoGravity() ? 0 : gravityAcceleration;
|
||||||
gravityDragPerTick + (gravityAcceleration * (double) gravityTickCount),
|
|
||||||
gravityTerminalVelocity) : 0;
|
|
||||||
|
|
||||||
final Vector deltaPos = new Vector(
|
final Vector deltaPos = new Vector(
|
||||||
getVelocity().getX() / tps,
|
getVelocity().getX() / tps,
|
||||||
(getVelocity().getY() - gravityY) / tps,
|
getVelocity().getY() / tps - gravityY,
|
||||||
getVelocity().getZ() / tps
|
getVelocity().getZ() / tps
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -591,6 +603,8 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
|
|
||||||
this.velocity.setX(velocity.getX() * drag);
|
this.velocity.setX(velocity.getX() * drag);
|
||||||
this.velocity.setZ(velocity.getZ() * drag);
|
this.velocity.setZ(velocity.getZ() * drag);
|
||||||
|
if (!hasNoGravity())
|
||||||
|
this.velocity.setY(velocity.getY() * (1-gravityDragPerTick));
|
||||||
|
|
||||||
if (velocity.equals(new Vector())) {
|
if (velocity.equals(new Vector())) {
|
||||||
this.velocity.zero();
|
this.velocity.zero();
|
||||||
@ -982,15 +996,6 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
return gravityAcceleration;
|
return gravityAcceleration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the maximum gravity velocity.
|
|
||||||
*
|
|
||||||
* @return the maximum gravity velocity in block
|
|
||||||
*/
|
|
||||||
public double getGravityTerminalVelocity() {
|
|
||||||
return gravityTerminalVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of tick this entity has been applied gravity.
|
* Gets the number of tick this entity has been applied gravity.
|
||||||
*
|
*
|
||||||
@ -1005,13 +1010,11 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
*
|
*
|
||||||
* @param gravityDragPerTick the gravity drag per tick in block
|
* @param gravityDragPerTick the gravity drag per tick in block
|
||||||
* @param gravityAcceleration the gravity acceleration in block
|
* @param gravityAcceleration the gravity acceleration in block
|
||||||
* @param gravityTerminalVelocity the gravity terminal velocity (maximum) in block
|
|
||||||
* @see <a href="https://minecraft.gamepedia.com/Entity#Motion_of_entities">Entities motion</a>
|
* @see <a href="https://minecraft.gamepedia.com/Entity#Motion_of_entities">Entities motion</a>
|
||||||
*/
|
*/
|
||||||
public void setGravity(double gravityDragPerTick, double gravityAcceleration, double gravityTerminalVelocity) {
|
public void setGravity(double gravityDragPerTick, double gravityAcceleration) {
|
||||||
this.gravityDragPerTick = gravityDragPerTick;
|
this.gravityDragPerTick = gravityDragPerTick;
|
||||||
this.gravityAcceleration = gravityAcceleration;
|
this.gravityAcceleration = gravityAcceleration;
|
||||||
this.gravityTerminalVelocity = gravityTerminalVelocity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1620,16 +1623,127 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
|||||||
return Objects.requireNonNullElse(this.customSynchronizationCooldown, SYNCHRONIZATION_COOLDOWN);
|
return Objects.requireNonNullElse(this.customSynchronizationCooldown, SYNCHRONIZATION_COOLDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public <T extends Entity> @NotNull Acquirable<T> getAcquirable() {
|
public <T extends Entity> @NotNull Acquirable<T> getAcquirable() {
|
||||||
return (Acquirable<T>) acquirable;
|
return (Acquirable<T>) acquirable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public <T extends Entity> @NotNull Acquirable<T> getAcquirable(@NotNull Class<T> clazz) {
|
public <T extends Entity> @NotNull Acquirable<T> getAcquirable(@NotNull Class<T> clazz) {
|
||||||
return (Acquirable<T>) acquirable;
|
return (Acquirable<T>) acquirable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||||
|
return tag.read(nbtCompound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
|
tag.write(nbtCompound, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Entity's {@link gravityAcceleration} and {@link gravityDragPerTick} fields to
|
||||||
|
* the default values according to <a href="https://minecraft.fandom.com/wiki/Entity#Motion_of_entities">Motion of entities</a>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("JavadocReference")
|
||||||
|
private void initializeDefaultGravity() {
|
||||||
|
// TODO Add support for these values in the data generator
|
||||||
|
// Acceleration
|
||||||
|
switch (entityType) {
|
||||||
|
// 0
|
||||||
|
case ITEM_FRAME:
|
||||||
|
this.gravityAcceleration = 0;
|
||||||
|
break;
|
||||||
|
// 0.03
|
||||||
|
case EGG:
|
||||||
|
case FISHING_BOBBER:
|
||||||
|
case EXPERIENCE_BOTTLE:
|
||||||
|
case ENDER_PEARL:
|
||||||
|
case POTION:
|
||||||
|
case SNOWBALL:
|
||||||
|
this.gravityAcceleration = 0.03;
|
||||||
|
break;
|
||||||
|
// 0.04
|
||||||
|
case BOAT:
|
||||||
|
case TNT:
|
||||||
|
case FALLING_BLOCK:
|
||||||
|
case ITEM:
|
||||||
|
case MINECART:
|
||||||
|
this.gravityAcceleration = 0.04;
|
||||||
|
break;
|
||||||
|
// 0.05
|
||||||
|
case ARROW:
|
||||||
|
case SPECTRAL_ARROW:
|
||||||
|
case TRIDENT:
|
||||||
|
this.gravityAcceleration = 0.05;
|
||||||
|
break;
|
||||||
|
// 0.06
|
||||||
|
case LLAMA_SPIT:
|
||||||
|
this.gravityAcceleration = 0.06;
|
||||||
|
break;
|
||||||
|
// 0.1
|
||||||
|
case FIREBALL:
|
||||||
|
case WITHER_SKULL:
|
||||||
|
case DRAGON_FIREBALL:
|
||||||
|
this.gravityAcceleration = 0.1;
|
||||||
|
break;
|
||||||
|
// 0.08
|
||||||
|
default:
|
||||||
|
this.gravityAcceleration = 0.08;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drag
|
||||||
|
switch (entityType) {
|
||||||
|
// 0
|
||||||
|
case BOAT:
|
||||||
|
this.gravityDragPerTick = 0;
|
||||||
|
break;
|
||||||
|
// 0.01
|
||||||
|
case LLAMA_SPIT:
|
||||||
|
case ENDER_PEARL:
|
||||||
|
case POTION:
|
||||||
|
case SNOWBALL:
|
||||||
|
case EGG:
|
||||||
|
case TRIDENT:
|
||||||
|
case SPECTRAL_ARROW:
|
||||||
|
case ARROW:
|
||||||
|
this.gravityDragPerTick = 0.01;
|
||||||
|
break;
|
||||||
|
// 0.05
|
||||||
|
case MINECART:
|
||||||
|
this.gravityDragPerTick = 0.05;
|
||||||
|
break;
|
||||||
|
// 0.08
|
||||||
|
case FISHING_BOBBER:
|
||||||
|
this.gravityDragPerTick = 0.08;
|
||||||
|
break;
|
||||||
|
// 0.02
|
||||||
|
default:
|
||||||
|
this.gravityDragPerTick = 0.02;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies knockback to the entity
|
||||||
|
*
|
||||||
|
* @param strength the strength of the knockback, 0.4 is the vanilla value for a bare hand hit
|
||||||
|
* @param x knockback on x axle, for default knockback use the following formula <pre>sin(attacker.yaw * (pi/180))</pre>
|
||||||
|
* @param z knockback on z axle, for default knockback use the following formula <pre>-cos(attacker.yaw * (pi/180))</pre>
|
||||||
|
*/
|
||||||
|
public void takeKnockback(final float strength, final double x, final double z) {
|
||||||
|
if (strength > 0) {
|
||||||
|
//TODO check possible side effects of unnatural TPS (other than 20TPS)
|
||||||
|
final Vector velocityModifier = new Vector(x, 0d, z).normalize().multiply(strength * MinecraftServer.TICK_PER_SECOND / 2);
|
||||||
|
this.velocity.setX(velocity.getX() / 2d - velocityModifier.getX());
|
||||||
|
this.velocity.setY(onGround ? Math.min(.4d, velocity.getY() / 2d + strength) * MinecraftServer.TICK_PER_SECOND : velocity.getY());
|
||||||
|
this.velocity.setZ(velocity.getZ() / 2d - velocityModifier.getZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum Pose {
|
public enum Pose {
|
||||||
STANDING,
|
STANDING,
|
||||||
FALL_FLYING,
|
FALL_FLYING,
|
||||||
|
@ -47,7 +47,6 @@ public class EntityProjectile extends Entity {
|
|||||||
if (getEntityMeta() instanceof ProjectileMeta) {
|
if (getEntityMeta() instanceof ProjectileMeta) {
|
||||||
((ProjectileMeta) getEntityMeta()).setShooter(this.shooter);
|
((ProjectileMeta) getEntityMeta()).setShooter(this.shooter);
|
||||||
}
|
}
|
||||||
setGravity(0.02f, 0.04f, 1.96f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -17,7 +17,6 @@ public class ExperienceOrb extends Entity {
|
|||||||
|
|
||||||
public ExperienceOrb(short experienceCount, @NotNull Position spawnPosition) {
|
public ExperienceOrb(short experienceCount, @NotNull Position spawnPosition) {
|
||||||
super(EntityType.EXPERIENCE_ORB, spawnPosition);
|
super(EntityType.EXPERIENCE_ORB, spawnPosition);
|
||||||
setGravity(0.02f, 0.04f, 1.96f);
|
|
||||||
setBoundingBox(0.5f, 0.5f, 0.5f);
|
setBoundingBox(0.5f, 0.5f, 0.5f);
|
||||||
//todo vanilla sets random velocity here?
|
//todo vanilla sets random velocity here?
|
||||||
this.experienceCount = experienceCount;
|
this.experienceCount = experienceCount;
|
||||||
|
@ -43,7 +43,6 @@ public class ItemEntity extends Entity {
|
|||||||
public ItemEntity(@NotNull ItemStack itemStack, @NotNull Position spawnPosition) {
|
public ItemEntity(@NotNull ItemStack itemStack, @NotNull Position spawnPosition) {
|
||||||
super(EntityType.ITEM, spawnPosition);
|
super(EntityType.ITEM, spawnPosition);
|
||||||
setItemStack(itemStack);
|
setItemStack(itemStack);
|
||||||
setGravity(0.02f, 0.04f, 1.96f);
|
|
||||||
setBoundingBox(0.25f, 0.25f, 0.25f);
|
setBoundingBox(0.25f, 0.25f, 0.25f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,6 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
*/
|
*/
|
||||||
public LivingEntity(@NotNull EntityType entityType, @NotNull UUID uuid) {
|
public LivingEntity(@NotNull EntityType entityType, @NotNull UUID uuid) {
|
||||||
this(entityType, uuid, new Position());
|
this(entityType, uuid, new Position());
|
||||||
setGravity(0.02f, 0.08f, 3.92f);
|
|
||||||
initEquipments();
|
initEquipments();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +103,6 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public LivingEntity(@NotNull EntityType entityType, @NotNull UUID uuid, @NotNull Position spawnPosition) {
|
public LivingEntity(@NotNull EntityType entityType, @NotNull UUID uuid, @NotNull Position spawnPosition) {
|
||||||
super(entityType, uuid, spawnPosition);
|
super(entityType, uuid, spawnPosition);
|
||||||
setGravity(0.02f, 0.08f, 3.92f);
|
|
||||||
initEquipments();
|
initEquipments();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -781,4 +779,18 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies knockback
|
||||||
|
* <p>
|
||||||
|
* Note: The strength is reduced based on knockback resistance
|
||||||
|
*
|
||||||
|
* @param strength the strength of the knockback, 0.4 is the vanilla value for a bare hand hit
|
||||||
|
* @param x knockback on x axle, for default knockback use the following formula <pre>sin(attacker.yaw * (pi/180))</pre>
|
||||||
|
* @param z knockback on z axle, for default knockback use the following formula <pre>-cos(attacker.yaw * (pi/180))</pre>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void takeKnockback(float strength, final double x, final double z) {
|
||||||
|
strength *= 1 - getAttributeValue(Attribute.KNOCKBACK_RESISTANCE);
|
||||||
|
super.takeKnockback(strength, x, z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.entity;
|
package net.minestom.server.entity;
|
||||||
|
|
||||||
import com.google.common.collect.Queues;
|
|
||||||
import net.kyori.adventure.audience.MessageType;
|
import net.kyori.adventure.audience.MessageType;
|
||||||
import net.kyori.adventure.bossbar.BossBar;
|
import net.kyori.adventure.bossbar.BossBar;
|
||||||
import net.kyori.adventure.identity.Identified;
|
import net.kyori.adventure.identity.Identified;
|
||||||
@ -87,6 +86,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
private final AtomicInteger teleportId = new AtomicInteger();
|
private final AtomicInteger teleportId = new AtomicInteger();
|
||||||
private int receivedTeleportId;
|
private int receivedTeleportId;
|
||||||
|
|
||||||
private final Queue<ClientPlayPacket> packets = Queues.newConcurrentLinkedQueue();
|
private final Queue<ClientPlayPacket> packets = new ConcurrentLinkedQueue<>();
|
||||||
private final boolean levelFlat;
|
private final boolean levelFlat;
|
||||||
private final PlayerSettings settings;
|
private final PlayerSettings settings;
|
||||||
private float exp;
|
private float exp;
|
||||||
@ -1379,9 +1379,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
* @param entity the entity to spectate
|
* @param entity the entity to spectate
|
||||||
*/
|
*/
|
||||||
public void spectate(@NotNull Entity entity) {
|
public void spectate(@NotNull Entity entity) {
|
||||||
CameraPacket cameraPacket = new CameraPacket();
|
playerConnection.sendPacket(new CameraPacket(entity));
|
||||||
cameraPacket.cameraId = entity.getEntityId();
|
|
||||||
playerConnection.sendPacket(cameraPacket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,7 @@ public class DoNothingGoal extends GoalSelector {
|
|||||||
public DoNothingGoal(EntityCreature entityCreature, long time, float chance) {
|
public DoNothingGoal(EntityCreature entityCreature, long time, float chance) {
|
||||||
super(entityCreature);
|
super(entityCreature);
|
||||||
this.time = time;
|
this.time = time;
|
||||||
this.chance = MathUtils.clampFloat(chance, 0, 1);
|
this.chance = MathUtils.clamp(chance, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -8,8 +8,11 @@ import net.minestom.server.entity.Entity;
|
|||||||
import net.minestom.server.entity.LivingEntity;
|
import net.minestom.server.entity.LivingEntity;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.sound.SoundEvent;
|
import net.minestom.server.sound.SoundEvent;
|
||||||
|
import net.minestom.server.tag.Tag;
|
||||||
|
import net.minestom.server.tag.TagHandler;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a type of damage, required when calling {@link LivingEntity#damage(DamageType, float)}
|
* Represents a type of damage, required when calling {@link LivingEntity#damage(DamageType, float)}
|
||||||
@ -19,7 +22,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
* Be aware that this class implements {@link DataContainer}
|
* Be aware that this class implements {@link DataContainer}
|
||||||
* so you can add your own data to an already existing damage type without any wrapper.
|
* so you can add your own data to an already existing damage type without any wrapper.
|
||||||
*/
|
*/
|
||||||
public class DamageType implements DataContainer {
|
public class DamageType implements TagHandler, DataContainer {
|
||||||
|
|
||||||
public static final DamageType VOID = new DamageType("attack.outOfWorld");
|
public static final DamageType VOID = new DamageType("attack.outOfWorld");
|
||||||
public static final DamageType GRAVITY = new DamageType("attack.fall");
|
public static final DamageType GRAVITY = new DamageType("attack.fall");
|
||||||
@ -30,6 +33,8 @@ public class DamageType implements DataContainer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final String identifier;
|
private final String identifier;
|
||||||
|
private final Object nbtLock = new Object();
|
||||||
|
private final NBTCompound nbt = new NBTCompound();
|
||||||
private Data data;
|
private Data data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,4 +164,18 @@ public class DamageType implements DataContainer {
|
|||||||
public void setData(Data data) {
|
public void setData(Data data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||||
|
synchronized (nbtLock) {
|
||||||
|
return tag.read(nbt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
|
synchronized (nbtLock) {
|
||||||
|
tag.write(nbt, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import java.net.URL;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
public class ExtensionManager {
|
public class ExtensionManager {
|
||||||
@ -379,8 +380,14 @@ public class ExtensionManager {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private DiscoveredExtension discoverFromJar(@NotNull File file) {
|
private DiscoveredExtension discoverFromJar(@NotNull File file) {
|
||||||
try (ZipFile f = new ZipFile(file);
|
try (ZipFile f = new ZipFile(file);) {
|
||||||
InputStreamReader reader = new InputStreamReader(f.getInputStream(f.getEntry("extension.json")))) {
|
|
||||||
|
ZipEntry entry = f.getEntry("extension.json");
|
||||||
|
|
||||||
|
if (entry == null)
|
||||||
|
throw new IllegalStateException("Missing extension.json in extension " + file.getName() + ".");
|
||||||
|
|
||||||
|
InputStreamReader reader = new InputStreamReader(f.getInputStream(entry));
|
||||||
|
|
||||||
// Initialize DiscoveredExtension from GSON.
|
// Initialize DiscoveredExtension from GSON.
|
||||||
DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class);
|
DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.minestom.server.extras.velocity;
|
package net.minestom.server.extras.velocity;
|
||||||
|
|
||||||
import com.google.common.net.InetAddresses;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.entity.PlayerSkin;
|
import net.minestom.server.entity.PlayerSkin;
|
||||||
import net.minestom.server.utils.binary.BinaryReader;
|
import net.minestom.server.utils.binary.BinaryReader;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
@ -73,7 +74,12 @@ public final class VelocityProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static InetAddress readAddress(@NotNull BinaryReader reader) {
|
public static InetAddress readAddress(@NotNull BinaryReader reader) {
|
||||||
return InetAddresses.forString(reader.readSizedString());
|
try {
|
||||||
|
return InetAddress.getByName(reader.readSizedString());
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
MinecraftServer.getExceptionManager().handleException(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlayerSkin readSkin(@NotNull BinaryReader reader) {
|
public static PlayerSkin readSkin(@NotNull BinaryReader reader) {
|
||||||
|
@ -16,6 +16,8 @@ import net.minestom.server.instance.block.CustomBlock;
|
|||||||
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
||||||
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
|
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
|
||||||
import net.minestom.server.network.player.PlayerConnection;
|
import net.minestom.server.network.player.PlayerConnection;
|
||||||
|
import net.minestom.server.tag.Tag;
|
||||||
|
import net.minestom.server.tag.TagHandler;
|
||||||
import net.minestom.server.utils.PacketUtils;
|
import net.minestom.server.utils.PacketUtils;
|
||||||
import net.minestom.server.utils.Position;
|
import net.minestom.server.utils.Position;
|
||||||
import net.minestom.server.utils.binary.BinaryReader;
|
import net.minestom.server.utils.binary.BinaryReader;
|
||||||
@ -27,6 +29,7 @@ import net.minestom.server.world.biomes.Biome;
|
|||||||
import net.minestom.server.world.biomes.BiomeManager;
|
import net.minestom.server.world.biomes.BiomeManager;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -47,7 +50,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
* You generally want to avoid storing references of this object as this could lead to a huge memory leak,
|
* You generally want to avoid storing references of this object as this could lead to a huge memory leak,
|
||||||
* you should store the chunk coordinates instead.
|
* you should store the chunk coordinates instead.
|
||||||
*/
|
*/
|
||||||
public abstract class Chunk implements Viewable, Tickable, DataContainer {
|
public abstract class Chunk implements Viewable, Tickable, TagHandler, DataContainer {
|
||||||
|
|
||||||
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||||
protected static final BiomeManager BIOME_MANAGER = MinecraftServer.getBiomeManager();
|
protected static final BiomeManager BIOME_MANAGER = MinecraftServer.getBiomeManager();
|
||||||
@ -75,6 +78,7 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
|
|||||||
protected PFColumnarSpace columnarSpace;
|
protected PFColumnarSpace columnarSpace;
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
|
private final NBTCompound nbt = new NBTCompound();
|
||||||
protected Data data;
|
protected Data data;
|
||||||
|
|
||||||
public Chunk(@NotNull Instance instance, @Nullable Biome[] biomes, int chunkX, int chunkZ, boolean shouldGenerate) {
|
public Chunk(@NotNull Instance instance, @Nullable Biome[] biomes, int chunkX, int chunkZ, boolean shouldGenerate) {
|
||||||
@ -480,6 +484,16 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
|
|||||||
return unmodifiableViewers;
|
return unmodifiableViewers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||||
|
return tag.read(nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
|
tag.write(nbt, value);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Data getData() {
|
public Data getData() {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.instance;
|
package net.minestom.server.instance;
|
||||||
|
|
||||||
import com.google.common.collect.Queues;
|
|
||||||
import net.kyori.adventure.identity.Identity;
|
import net.kyori.adventure.identity.Identity;
|
||||||
import net.kyori.adventure.pointer.Pointers;
|
import net.kyori.adventure.pointer.Pointers;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
@ -29,6 +28,8 @@ import net.minestom.server.instance.block.CustomBlock;
|
|||||||
import net.minestom.server.network.packet.server.play.BlockActionPacket;
|
import net.minestom.server.network.packet.server.play.BlockActionPacket;
|
||||||
import net.minestom.server.network.packet.server.play.TimeUpdatePacket;
|
import net.minestom.server.network.packet.server.play.TimeUpdatePacket;
|
||||||
import net.minestom.server.storage.StorageLocation;
|
import net.minestom.server.storage.StorageLocation;
|
||||||
|
import net.minestom.server.tag.Tag;
|
||||||
|
import net.minestom.server.tag.TagHandler;
|
||||||
import net.minestom.server.thread.ThreadProvider;
|
import net.minestom.server.thread.ThreadProvider;
|
||||||
import net.minestom.server.utils.BlockPosition;
|
import net.minestom.server.utils.BlockPosition;
|
||||||
import net.minestom.server.utils.PacketUtils;
|
import net.minestom.server.utils.PacketUtils;
|
||||||
@ -44,9 +45,11 @@ import net.minestom.server.world.DimensionType;
|
|||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,7 +63,7 @@ import java.util.function.Consumer;
|
|||||||
* you need to be sure to signal the {@link UpdateManager} of the changes using
|
* you need to be sure to signal the {@link UpdateManager} of the changes using
|
||||||
* {@link UpdateManager#signalChunkLoad(Chunk)} and {@link UpdateManager#signalChunkUnload(Chunk)}.
|
* {@link UpdateManager#signalChunkLoad(Chunk)} and {@link UpdateManager#signalChunkUnload(Chunk)}.
|
||||||
*/
|
*/
|
||||||
public abstract class Instance implements BlockModifier, Tickable, EventHandler<InstanceEvent>, DataContainer, PacketGroupingAudience {
|
public abstract class Instance implements BlockModifier, Tickable, TagHandler, PacketGroupingAudience, EventHandler<InstanceEvent>, DataContainer {
|
||||||
|
|
||||||
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||||
protected static final UpdateManager UPDATE_MANAGER = MinecraftServer.getUpdateManager();
|
protected static final UpdateManager UPDATE_MANAGER = MinecraftServer.getUpdateManager();
|
||||||
@ -98,9 +101,11 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler<
|
|||||||
protected UUID uniqueId;
|
protected UUID uniqueId;
|
||||||
|
|
||||||
// list of scheduled tasks to be executed during the next instance tick
|
// list of scheduled tasks to be executed during the next instance tick
|
||||||
protected final Queue<Consumer<Instance>> nextTick = Queues.newConcurrentLinkedQueue();
|
protected final Queue<Consumer<Instance>> nextTick = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
// instance custom data
|
// instance custom data
|
||||||
|
private final Object nbtLock = new Object();
|
||||||
|
private final NBTCompound nbt = new NBTCompound();
|
||||||
private Data data;
|
private Data data;
|
||||||
|
|
||||||
// the explosion supplier
|
// the explosion supplier
|
||||||
@ -1061,6 +1066,20 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler<
|
|||||||
this.worldBorder.update();
|
this.worldBorder.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||||
|
synchronized (nbtLock) {
|
||||||
|
return tag.read(nbt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
|
synchronized (nbtLock) {
|
||||||
|
tag.write(nbt, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an explosion at the given position with the given strength.
|
* Creates an explosion at the given position with the given strength.
|
||||||
* The algorithm used to compute damages is provided by {@link #getExplosionSupplier()}.
|
* The algorithm used to compute damages is provided by {@link #getExplosionSupplier()}.
|
||||||
|
@ -750,10 +750,7 @@ public class InstanceContainer extends Instance {
|
|||||||
* @param blockStateId the new state of the block
|
* @param blockStateId the new state of the block
|
||||||
*/
|
*/
|
||||||
private void sendBlockChange(@NotNull Chunk chunk, @NotNull BlockPosition blockPosition, short blockStateId) {
|
private void sendBlockChange(@NotNull Chunk chunk, @NotNull BlockPosition blockPosition, short blockStateId) {
|
||||||
BlockChangePacket blockChangePacket = new BlockChangePacket();
|
chunk.sendPacketToViewers(new BlockChangePacket(blockPosition, blockStateId));
|
||||||
blockChangePacket.blockPosition = blockPosition;
|
|
||||||
blockChangePacket.blockStateId = blockStateId;
|
|
||||||
chunk.sendPacketToViewers(blockChangePacket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,10 +5,13 @@ import net.minestom.server.data.DataContainer;
|
|||||||
import net.minestom.server.inventory.click.InventoryClickProcessor;
|
import net.minestom.server.inventory.click.InventoryClickProcessor;
|
||||||
import net.minestom.server.inventory.condition.InventoryCondition;
|
import net.minestom.server.inventory.condition.InventoryCondition;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
|
import net.minestom.server.tag.Tag;
|
||||||
|
import net.minestom.server.tag.TagHandler;
|
||||||
import net.minestom.server.utils.MathUtils;
|
import net.minestom.server.utils.MathUtils;
|
||||||
import net.minestom.server.utils.validate.Check;
|
import net.minestom.server.utils.validate.Check;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -19,7 +22,7 @@ import java.util.function.UnaryOperator;
|
|||||||
/**
|
/**
|
||||||
* Represents an inventory where items can be modified/retrieved.
|
* Represents an inventory where items can be modified/retrieved.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractInventory implements InventoryClickHandler, DataContainer {
|
public abstract class AbstractInventory implements InventoryClickHandler, TagHandler, DataContainer {
|
||||||
|
|
||||||
private final int size;
|
private final int size;
|
||||||
protected final ItemStack[] itemStacks;
|
protected final ItemStack[] itemStacks;
|
||||||
@ -29,6 +32,8 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo
|
|||||||
// the click processor which process all the clicks in the inventory
|
// the click processor which process all the clicks in the inventory
|
||||||
protected final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
|
protected final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
|
||||||
|
|
||||||
|
private final Object nbtLock = new Object();
|
||||||
|
private final NBTCompound nbt = new NBTCompound();
|
||||||
private Data data;
|
private Data data;
|
||||||
|
|
||||||
protected AbstractInventory(int size) {
|
protected AbstractInventory(int size) {
|
||||||
@ -210,6 +215,20 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||||
|
synchronized (nbtLock) {
|
||||||
|
return tag.read(nbt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
|
synchronized (nbtLock) {
|
||||||
|
tag.write(nbt, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Data getData() {
|
public @Nullable Data getData() {
|
||||||
return data;
|
return data;
|
||||||
|
@ -403,16 +403,11 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl
|
|||||||
public boolean doubleClick(@NotNull Player player, int slot) {
|
public boolean doubleClick(@NotNull Player player, int slot) {
|
||||||
final ItemStack cursor = getCursorItem();
|
final ItemStack cursor = getCursorItem();
|
||||||
final InventoryClickResult clickResult = clickProcessor.doubleClick(this, null, player, slot, cursor);
|
final InventoryClickResult clickResult = clickProcessor.doubleClick(this, null, player, slot, cursor);
|
||||||
|
|
||||||
if (clickResult == null)
|
if (clickResult == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (clickResult.doRefresh())
|
if (clickResult.doRefresh())
|
||||||
update();
|
update();
|
||||||
|
|
||||||
setItemStack(slot, OFFSET, clickResult.getClicked());
|
|
||||||
setCursorItem(clickResult.getCursor());
|
setCursorItem(clickResult.getCursor());
|
||||||
|
|
||||||
return !clickResult.isCancel();
|
return !clickResult.isCancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ public class ItemMeta implements TagReadable, Writeable {
|
|||||||
this.canDestroy = new HashSet<>(metaBuilder.canDestroy);
|
this.canDestroy = new HashSet<>(metaBuilder.canDestroy);
|
||||||
this.canPlaceOn = new HashSet<>(metaBuilder.canPlaceOn);
|
this.canPlaceOn = new HashSet<>(metaBuilder.canPlaceOn);
|
||||||
|
|
||||||
this.nbt = metaBuilder.nbt;
|
this.nbt = metaBuilder.nbt();
|
||||||
this.emptyBuilder = metaBuilder.getSupplier().get();
|
this.emptyBuilder = metaBuilder.getSupplier().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,11 +117,6 @@ public class ItemMeta implements TagReadable, Writeable {
|
|||||||
return tag.read(nbt);
|
return tag.read(nbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasTag(@NotNull Tag<?> tag) {
|
|
||||||
return nbt.containsKey(tag.getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull NBTCompound toNBT() {
|
public @NotNull NBTCompound toNBT() {
|
||||||
return nbt.deepClone();
|
return nbt.deepClone();
|
||||||
}
|
}
|
||||||
@ -169,12 +164,7 @@ public class ItemMeta implements TagReadable, Writeable {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
public <T> T getOrDefault(@NotNull Tag<T> tag, @Nullable T defaultValue) {
|
public <T> T getOrDefault(@NotNull Tag<T> tag, @Nullable T defaultValue) {
|
||||||
var key = tag.getKey();
|
return tag.defaultValue(defaultValue).read(toNBT());
|
||||||
if (nbt.containsKey(key)) {
|
|
||||||
return tag.read(toNBT());
|
|
||||||
} else {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,6 @@ package net.minestom.server.item;
|
|||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.minestom.server.adventure.AdventureSerializer;
|
|
||||||
import net.minestom.server.instance.block.Block;
|
import net.minestom.server.instance.block.Block;
|
||||||
import net.minestom.server.item.attribute.ItemAttribute;
|
import net.minestom.server.item.attribute.ItemAttribute;
|
||||||
import net.minestom.server.tag.Tag;
|
import net.minestom.server.tag.Tag;
|
||||||
@ -15,12 +14,17 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jglrxavpok.hephaistos.nbt.*;
|
import org.jglrxavpok.hephaistos.nbt.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class ItemMetaBuilder implements TagWritable {
|
public abstract class ItemMetaBuilder implements TagWritable {
|
||||||
|
|
||||||
protected NBTCompound nbt = new NBTCompound();
|
private static final AtomicReferenceFieldUpdater<ItemMetaBuilder, NBTCompound> NBT_UPDATER =
|
||||||
|
AtomicReferenceFieldUpdater.newUpdater(ItemMetaBuilder.class, NBTCompound.class, "nbt");
|
||||||
|
|
||||||
|
protected volatile boolean built = false;
|
||||||
|
private volatile NBTCompound nbt = new NBTCompound();
|
||||||
|
|
||||||
protected int damage;
|
protected int damage;
|
||||||
protected boolean unbreakable;
|
protected boolean unbreakable;
|
||||||
@ -36,21 +40,21 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder damage(int damage) {
|
public @NotNull ItemMetaBuilder damage(int damage) {
|
||||||
this.damage = damage;
|
this.damage = damage;
|
||||||
this.nbt.setInt("Damage", damage);
|
mutateNbt(compound -> compound.setInt("Damage", damage));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder unbreakable(boolean unbreakable) {
|
public @NotNull ItemMetaBuilder unbreakable(boolean unbreakable) {
|
||||||
this.unbreakable = unbreakable;
|
this.unbreakable = unbreakable;
|
||||||
this.nbt.setByte("Unbreakable", (byte) (unbreakable ? 1 : 0));
|
mutateNbt(compound -> compound.setByte("Unbreakable", (byte) (unbreakable ? 1 : 0)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder hideFlag(int hideFlag) {
|
public @NotNull ItemMetaBuilder hideFlag(int hideFlag) {
|
||||||
this.hideFlag = hideFlag;
|
this.hideFlag = hideFlag;
|
||||||
this.nbt.setInt("HideFlags", hideFlag);
|
mutateNbt(compound -> compound.setInt("HideFlags", hideFlag));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +83,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
|
|
||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) {
|
public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) {
|
||||||
this.lore = lore;
|
this.lore = new ArrayList<>(lore);
|
||||||
handleCompound("display", nbtCompound -> {
|
handleCompound("display", nbtCompound -> {
|
||||||
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
|
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
|
||||||
for (Component line : lore) {
|
for (Component line : lore) {
|
||||||
@ -98,8 +102,8 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
|
|
||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
|
public @NotNull ItemMetaBuilder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
|
||||||
this.enchantmentMap = enchantments;
|
this.enchantmentMap = new HashMap<>(enchantments);
|
||||||
handleMap(enchantmentMap, "Enchantments", nbt, () -> {
|
handleMap(enchantmentMap, "Enchantments", () -> {
|
||||||
NBTUtils.writeEnchant(nbt, "Enchantments", enchantmentMap);
|
NBTUtils.writeEnchant(nbt, "Enchantments", enchantmentMap);
|
||||||
return nbt.get("Enchantments");
|
return nbt.get("Enchantments");
|
||||||
});
|
});
|
||||||
@ -115,16 +119,16 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
|
|
||||||
@Contract("-> this")
|
@Contract("-> this")
|
||||||
public @NotNull ItemMetaBuilder clearEnchantment() {
|
public @NotNull ItemMetaBuilder clearEnchantment() {
|
||||||
this.enchantmentMap.clear();
|
this.enchantmentMap = Collections.emptyMap();
|
||||||
enchantments(enchantmentMap);
|
enchantments(enchantmentMap);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder attributes(@NotNull List<@NotNull ItemAttribute> attributes) {
|
public @NotNull ItemMetaBuilder attributes(@NotNull List<@NotNull ItemAttribute> attributes) {
|
||||||
this.attributes = attributes;
|
this.attributes = new ArrayList<>(attributes);
|
||||||
|
|
||||||
handleCollection(attributes, "AttributeModifiers", nbt, () -> {
|
handleCollection(attributes, "AttributeModifiers", () -> {
|
||||||
NBTList<NBTCompound> attributesNBT = new NBTList<>(NBTTypes.TAG_Compound);
|
NBTList<NBTCompound> attributesNBT = new NBTList<>(NBTTypes.TAG_Compound);
|
||||||
for (ItemAttribute itemAttribute : attributes) {
|
for (ItemAttribute itemAttribute : attributes) {
|
||||||
final UUID uuid = itemAttribute.getUuid();
|
final UUID uuid = itemAttribute.getUuid();
|
||||||
@ -147,17 +151,16 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder customModelData(int customModelData) {
|
public @NotNull ItemMetaBuilder customModelData(int customModelData) {
|
||||||
this.customModelData = customModelData;
|
this.customModelData = customModelData;
|
||||||
this.nbt.setInt("CustomModelData", customModelData);
|
mutateNbt(compound -> compound.setInt("CustomModelData", customModelData));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder canPlaceOn(@NotNull Set<@NotNull Block> blocks) {
|
public @NotNull ItemMetaBuilder canPlaceOn(@NotNull Set<@NotNull Block> blocks) {
|
||||||
this.canPlaceOn = blocks;
|
this.canPlaceOn = new HashSet<>(blocks);
|
||||||
handleCollection(canPlaceOn, "CanPlaceOn", nbt, () -> {
|
handleCollection(canPlaceOn, "CanPlaceOn", () -> {
|
||||||
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
||||||
canPlaceOn.forEach(block -> list.add(new NBTString(block.getName())));
|
canPlaceOn.forEach(block -> list.add(new NBTString(block.getName())));
|
||||||
nbt.set("CanPlaceOn", list);
|
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
@ -170,11 +173,10 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
|
|
||||||
@Contract("_ -> this")
|
@Contract("_ -> this")
|
||||||
public @NotNull ItemMetaBuilder canDestroy(@NotNull Set<@NotNull Block> blocks) {
|
public @NotNull ItemMetaBuilder canDestroy(@NotNull Set<@NotNull Block> blocks) {
|
||||||
this.canDestroy = blocks;
|
this.canDestroy = new HashSet<>(blocks);
|
||||||
handleCollection(canDestroy, "CanDestroy", nbt, () -> {
|
handleCollection(canDestroy, "CanDestroy", () -> {
|
||||||
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
||||||
canDestroy.forEach(block -> list.add(new NBTString(block.getName())));
|
canDestroy.forEach(block -> list.add(new NBTString(block.getName())));
|
||||||
nbt.set("CanDestroy", list);
|
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
@ -187,7 +189,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
tag.write(nbt, value);
|
mutateNbt(compound -> tag.write(compound, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> @NotNull ItemMetaBuilder set(@NotNull Tag<T> tag, @Nullable T value) {
|
public <T> @NotNull ItemMetaBuilder set(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
@ -202,8 +204,27 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
|
|
||||||
protected abstract @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier();
|
protected abstract @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier();
|
||||||
|
|
||||||
|
protected synchronized void mutateNbt(Consumer<NBTCompound> consumer) {
|
||||||
|
if (built) {
|
||||||
|
built = false;
|
||||||
|
final var currentNbt = nbt;
|
||||||
|
NBT_UPDATER.compareAndSet(this, currentNbt, currentNbt.deepClone());
|
||||||
|
}
|
||||||
|
consumer.accept(nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized NBTCompound nbt() {
|
||||||
|
return nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @NotNull ItemMeta generate() {
|
||||||
|
this.built = true;
|
||||||
|
return build();
|
||||||
|
}
|
||||||
|
|
||||||
protected void handleCompound(@NotNull String key,
|
protected void handleCompound(@NotNull String key,
|
||||||
@NotNull Consumer<@NotNull NBTCompound> consumer) {
|
@NotNull Consumer<@NotNull NBTCompound> consumer) {
|
||||||
|
mutateNbt(nbt -> {
|
||||||
NBTCompound compound = null;
|
NBTCompound compound = null;
|
||||||
boolean newNbt = false;
|
boolean newNbt = false;
|
||||||
if (nbt.containsKey(key)) {
|
if (nbt.containsKey(key)) {
|
||||||
@ -224,41 +245,44 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
} else if (!newNbt && compound.getSize() == 0) {
|
} else if (!newNbt && compound.getSize() == 0) {
|
||||||
this.nbt.removeTag(key);
|
this.nbt.removeTag(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleNullable(@Nullable Object value,
|
protected void handleNullable(@Nullable Object value,
|
||||||
@NotNull String key,
|
@NotNull String key,
|
||||||
@NotNull NBTCompound nbtCompound,
|
|
||||||
@NotNull Supplier<@NotNull NBT> supplier) {
|
@NotNull Supplier<@NotNull NBT> supplier) {
|
||||||
|
mutateNbt(compound -> {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
nbtCompound.set(key, supplier.get());
|
compound.set(key, supplier.get());
|
||||||
} else {
|
} else {
|
||||||
nbtCompound.removeTag(key);
|
compound.removeTag(key);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleCollection(@NotNull Collection<?> objects,
|
protected void handleCollection(@NotNull Collection<?> objects,
|
||||||
@NotNull String key,
|
@NotNull String key,
|
||||||
@NotNull NBTCompound nbtCompound,
|
|
||||||
@NotNull Supplier<@NotNull NBT> supplier) {
|
@NotNull Supplier<@NotNull NBT> supplier) {
|
||||||
|
mutateNbt(compound -> {
|
||||||
if (!objects.isEmpty()) {
|
if (!objects.isEmpty()) {
|
||||||
nbtCompound.set(key, supplier.get());
|
compound.set(key, supplier.get());
|
||||||
} else {
|
} else {
|
||||||
nbtCompound.removeTag(key);
|
compound.removeTag(key);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleMap(@NotNull Map<?, ?> objects,
|
protected void handleMap(@NotNull Map<?, ?> objects,
|
||||||
@NotNull String key,
|
@NotNull String key,
|
||||||
@NotNull NBTCompound nbtCompound,
|
|
||||||
@NotNull Supplier<@NotNull NBT> supplier) {
|
@NotNull Supplier<@NotNull NBT> supplier) {
|
||||||
|
mutateNbt(compound -> {
|
||||||
if (!objects.isEmpty()) {
|
if (!objects.isEmpty()) {
|
||||||
nbtCompound.set(key, supplier.get());
|
compound.set(key, supplier.get());
|
||||||
} else {
|
} else {
|
||||||
nbtCompound.removeTag(key);
|
compound.removeTag(key);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(value = "_, _ -> new", pure = true)
|
@Contract(value = "_, _ -> new", pure = true)
|
||||||
@ -271,5 +295,4 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
|||||||
|
|
||||||
public interface Provider<T extends ItemMetaBuilder> {
|
public interface Provider<T extends ItemMetaBuilder> {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -203,11 +203,6 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
|
|||||||
return meta.getTag(tag);
|
return meta.getTag(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasTag(@NotNull Tag<?> tag) {
|
|
||||||
return meta.hasTag(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull HoverEvent<HoverEvent.ShowItem> asHoverEvent(@NotNull UnaryOperator<HoverEvent.ShowItem> op) {
|
public @NotNull HoverEvent<HoverEvent.ShowItem> asHoverEvent(@NotNull UnaryOperator<HoverEvent.ShowItem> op) {
|
||||||
return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.of(this.material,
|
return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.of(this.material,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.minestom.server.item;
|
package net.minestom.server.item;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minestom.server.item.metadata.*;
|
import net.minestom.server.item.metadata.*;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@ -100,7 +100,7 @@ public class ItemStackBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
@Contract(value = "_ -> this")
|
@Contract(value = "_ -> this")
|
||||||
public @NotNull ItemStackBuilder stackingRule(@Nullable StackingRule stackingRule) {
|
public @NotNull ItemStackBuilder stackingRule(@Nullable StackingRule stackingRule) {
|
||||||
this.stackingRule = stackingRule;
|
this.stackingRule = stackingRule;
|
||||||
@ -109,9 +109,9 @@ public class ItemStackBuilder {
|
|||||||
|
|
||||||
@Contract(value = "-> new", pure = true)
|
@Contract(value = "-> new", pure = true)
|
||||||
public @NotNull ItemStack build() {
|
public @NotNull ItemStack build() {
|
||||||
if (amount > 0)
|
if (amount < 1)
|
||||||
return new ItemStack(material, amount, metaBuilder.build(), stackingRule);
|
|
||||||
return ItemStack.AIR;
|
return ItemStack.AIR;
|
||||||
|
return new ItemStack(material, amount, metaBuilder.generate(), stackingRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class DefaultMeta extends ItemMetaBuilder {
|
private static final class DefaultMeta extends ItemMetaBuilder {
|
||||||
@ -130,5 +130,4 @@ public class ItemStackBuilder {
|
|||||||
return DefaultMeta::new;
|
return DefaultMeta::new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,18 +45,20 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
|
|||||||
|
|
||||||
public Builder lodestoneTracked(boolean lodestoneTracked) {
|
public Builder lodestoneTracked(boolean lodestoneTracked) {
|
||||||
this.lodestoneTracked = lodestoneTracked;
|
this.lodestoneTracked = lodestoneTracked;
|
||||||
this.nbt.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0));
|
mutateNbt(compound -> compound.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder lodestoneDimension(@Nullable String lodestoneDimension) {
|
public Builder lodestoneDimension(@Nullable String lodestoneDimension) {
|
||||||
this.lodestoneDimension = lodestoneDimension;
|
this.lodestoneDimension = lodestoneDimension;
|
||||||
|
|
||||||
|
mutateNbt(compound -> {
|
||||||
if (lodestoneDimension != null) {
|
if (lodestoneDimension != null) {
|
||||||
this.nbt.setString("LodestoneDimension", lodestoneDimension);
|
compound.setString("LodestoneDimension", lodestoneDimension);
|
||||||
} else {
|
} else {
|
||||||
this.nbt.removeTag("LodestoneDimension");
|
compound.removeTag("LodestoneDimension");
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -64,15 +66,17 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
|
|||||||
public Builder lodestonePosition(@Nullable Position lodestonePosition) {
|
public Builder lodestonePosition(@Nullable Position lodestonePosition) {
|
||||||
this.lodestonePosition = lodestonePosition;
|
this.lodestonePosition = lodestonePosition;
|
||||||
|
|
||||||
|
mutateNbt(compound -> {
|
||||||
if (lodestonePosition != null) {
|
if (lodestonePosition != null) {
|
||||||
NBTCompound posCompound = new NBTCompound();
|
NBTCompound posCompound = new NBTCompound();
|
||||||
posCompound.setInt("X", (int) lodestonePosition.getX());
|
posCompound.setInt("X", (int) lodestonePosition.getX());
|
||||||
posCompound.setInt("Y", (int) lodestonePosition.getY());
|
posCompound.setInt("Y", (int) lodestonePosition.getY());
|
||||||
posCompound.setInt("Z", (int) lodestonePosition.getZ());
|
posCompound.setInt("Z", (int) lodestonePosition.getZ());
|
||||||
this.nbt.set("LodestonePos", posCompound);
|
compound.set("LodestonePos", posCompound);
|
||||||
} else {
|
} else {
|
||||||
this.nbt.removeTag("LodestonePos");
|
compound.removeTag("LodestonePos");
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
|
|||||||
if (!projectile.isAir()) {
|
if (!projectile.isAir()) {
|
||||||
chargedProjectiles.add(getItemCompound(projectile));
|
chargedProjectiles.add(getItemCompound(projectile));
|
||||||
}
|
}
|
||||||
this.nbt.set("ChargedProjectiles", chargedProjectiles);
|
mutateNbt(compound -> compound.set("ChargedProjectiles", chargedProjectiles));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
|
|||||||
chargedProjectiles.add(getItemCompound(projectile1));
|
chargedProjectiles.add(getItemCompound(projectile1));
|
||||||
chargedProjectiles.add(getItemCompound(projectile2));
|
chargedProjectiles.add(getItemCompound(projectile2));
|
||||||
chargedProjectiles.add(getItemCompound(projectile3));
|
chargedProjectiles.add(getItemCompound(projectile3));
|
||||||
this.nbt.set("ChargedProjectiles", chargedProjectiles);
|
mutateNbt(compound -> compound.set("ChargedProjectiles", chargedProjectiles));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
|
|||||||
*/
|
*/
|
||||||
public Builder charged(boolean charged) {
|
public Builder charged(boolean charged) {
|
||||||
this.charged = charged;
|
this.charged = charged;
|
||||||
this.nbt.setByte("Charged", (byte) (charged ? 1 : 0));
|
mutateNbt(compound -> compound.setByte("Charged", (byte) (charged ? 1 : 0)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,13 +35,13 @@ public class EnchantedBookMeta extends ItemMeta implements ItemMetaBuilder.Provi
|
|||||||
|
|
||||||
private Map<Enchantment, Short> enchantments = new HashMap<>();
|
private Map<Enchantment, Short> enchantments = new HashMap<>();
|
||||||
|
|
||||||
public @NotNull Builder enchantments(Map<Enchantment, Short> enchantments) {
|
public @NotNull Builder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
|
||||||
this.enchantments = enchantments;
|
this.enchantments = enchantments;
|
||||||
NBTUtils.writeEnchant(nbt, "StoredEnchantments", enchantments);
|
mutateNbt(compound -> NBTUtils.writeEnchant(compound, "StoredEnchantments", enchantments));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull Builder enchantment(Enchantment enchantment, short level) {
|
public @NotNull Builder enchantment(@NotNull Enchantment enchantment, short level) {
|
||||||
this.enchantments.put(enchantment, level);
|
this.enchantments.put(enchantment, level);
|
||||||
enchantments(enchantments);
|
enchantments(enchantments);
|
||||||
return this;
|
return this;
|
||||||
|
@ -28,7 +28,7 @@ public class FireworkEffectMeta extends ItemMeta implements ItemMetaBuilder.Prov
|
|||||||
|
|
||||||
public Builder effect(@Nullable FireworkEffect fireworkEffect) {
|
public Builder effect(@Nullable FireworkEffect fireworkEffect) {
|
||||||
this.fireworkEffect = fireworkEffect;
|
this.fireworkEffect = fireworkEffect;
|
||||||
this.nbt.set("Explosion", this.fireworkEffect.asCompound());
|
mutateNbt(compound -> compound.set("Explosion", this.fireworkEffect.asCompound()));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,18 +91,18 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
|
|||||||
|
|
||||||
public Builder mapId(int value) {
|
public Builder mapId(int value) {
|
||||||
this.mapId = value;
|
this.mapId = value;
|
||||||
this.nbt.setInt("map", mapId);
|
mutateNbt(compound -> compound.setInt("map", mapId));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder mapScaleDirection(int value) {
|
public Builder mapScaleDirection(int value) {
|
||||||
this.mapScaleDirection = value;
|
this.mapScaleDirection = value;
|
||||||
this.nbt.setInt("map_scale_direction", value);
|
mutateNbt(compound -> compound.setInt("map_scale_direction", value));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder decorations(List<MapDecoration> value) {
|
public Builder decorations(List<MapDecoration> value) {
|
||||||
this.decorations = value;
|
this.decorations = new ArrayList<>(value);
|
||||||
|
|
||||||
NBTList<NBTCompound> decorationsList = new NBTList<>(NBTTypes.TAG_Compound);
|
NBTList<NBTCompound> decorationsList = new NBTList<>(NBTTypes.TAG_Compound);
|
||||||
for (MapDecoration decoration : decorations) {
|
for (MapDecoration decoration : decorations) {
|
||||||
@ -115,7 +115,7 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
|
|||||||
|
|
||||||
decorationsList.add(decorationCompound);
|
decorationsList.add(decorationCompound);
|
||||||
}
|
}
|
||||||
this.nbt.set("Decorations", decorationsList);
|
mutateNbt(compound -> compound.set("Decorations", decorationsList));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -123,14 +123,16 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
|
|||||||
public Builder mapColor(Color value) {
|
public Builder mapColor(Color value) {
|
||||||
this.mapColor = value;
|
this.mapColor = value;
|
||||||
|
|
||||||
|
mutateNbt(nbt -> {
|
||||||
NBTCompound displayCompound;
|
NBTCompound displayCompound;
|
||||||
if (nbt.containsKey("display")) {
|
if (nbt.containsKey("display")) {
|
||||||
displayCompound = nbt.getCompound("display");
|
displayCompound = nbt.getCompound("display");
|
||||||
} else {
|
} else {
|
||||||
displayCompound = new NBTCompound();
|
displayCompound = new NBTCompound();
|
||||||
this.nbt.set("display", displayCompound);
|
nbt.set("display", displayCompound);
|
||||||
}
|
}
|
||||||
displayCompound.setInt("MapColor", mapColor.asRGB());
|
displayCompound.setInt("MapColor", mapColor.asRGB());
|
||||||
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider<Pot
|
|||||||
|
|
||||||
public Builder potionType(@NotNull PotionType potionType) {
|
public Builder potionType(@NotNull PotionType potionType) {
|
||||||
this.potionType = potionType;
|
this.potionType = potionType;
|
||||||
this.nbt.setString("Potion", potionType.getNamespaceID().asString());
|
mutateNbt(compound -> compound.setString("Potion", potionType.getNamespaceID().asString()));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,14 +71,14 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider<Pot
|
|||||||
|
|
||||||
potionList.add(potionCompound);
|
potionList.add(potionCompound);
|
||||||
}
|
}
|
||||||
this.nbt.set("CustomPotionEffects", potionList);
|
mutateNbt(compound -> compound.set("CustomPotionEffects", potionList));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder color(@NotNull Color color) {
|
public Builder color(@NotNull Color color) {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.nbt.setInt("CustomPotionColor", color.asRGB());
|
mutateNbt(compound -> compound.setInt("CustomPotionColor", color.asRGB()));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package net.minestom.server.item.metadata;
|
|||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.minestom.server.adventure.AdventureSerializer;
|
|
||||||
import net.minestom.server.item.ItemMeta;
|
import net.minestom.server.item.ItemMeta;
|
||||||
import net.minestom.server.item.ItemMetaBuilder;
|
import net.minestom.server.item.ItemMetaBuilder;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -53,22 +52,22 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid
|
|||||||
|
|
||||||
public Builder author(@Nullable String author) {
|
public Builder author(@Nullable String author) {
|
||||||
this.author = author;
|
this.author = author;
|
||||||
handleNullable(author, "author", nbt,
|
handleNullable(author, "author",
|
||||||
() -> new NBTString(Objects.requireNonNull(author)));
|
() -> new NBTString(Objects.requireNonNull(author)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder title(@Nullable String title) {
|
public Builder title(@Nullable String title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
handleNullable(title, "title", nbt,
|
handleNullable(title, "title",
|
||||||
() -> new NBTString(Objects.requireNonNull(title)));
|
() -> new NBTString(Objects.requireNonNull(title)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder pages(@NotNull List<@NotNull Component> pages) {
|
public Builder pages(@NotNull List<@NotNull Component> pages) {
|
||||||
this.pages = pages;
|
this.pages = new ArrayList<>(pages);
|
||||||
|
|
||||||
handleCollection(pages, "pages", nbt, () -> {
|
handleCollection(pages, "pages", () -> {
|
||||||
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
||||||
for (Component page : pages) {
|
for (Component page : pages) {
|
||||||
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));
|
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));
|
||||||
|
@ -86,35 +86,35 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide
|
|||||||
|
|
||||||
public Builder resolved(boolean resolved) {
|
public Builder resolved(boolean resolved) {
|
||||||
this.resolved = resolved;
|
this.resolved = resolved;
|
||||||
this.nbt.setByte("resolved", (byte) (resolved ? 1 : 0));
|
mutateNbt(compound -> compound.setByte("resolved", (byte) (resolved ? 1 : 0)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder generation(@Nullable WrittenBookGeneration generation) {
|
public Builder generation(@Nullable WrittenBookGeneration generation) {
|
||||||
this.generation = generation;
|
this.generation = generation;
|
||||||
handleNullable(generation, "generation", nbt,
|
handleNullable(generation, "generation",
|
||||||
() -> new NBTInt(Objects.requireNonNull(generation).ordinal()));
|
() -> new NBTInt(Objects.requireNonNull(generation).ordinal()));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder author(@Nullable String author) {
|
public Builder author(@Nullable String author) {
|
||||||
this.author = author;
|
this.author = author;
|
||||||
handleNullable(author, "author", nbt,
|
handleNullable(author, "author",
|
||||||
() -> new NBTString(Objects.requireNonNull(author)));
|
() -> new NBTString(Objects.requireNonNull(author)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder title(@Nullable String title) {
|
public Builder title(@Nullable String title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
handleNullable(title, "title", nbt,
|
handleNullable(title, "title",
|
||||||
() -> new NBTString(Objects.requireNonNull(title)));
|
() -> new NBTString(Objects.requireNonNull(title)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder pages(@NotNull List<@NotNull Component> pages) {
|
public Builder pages(@NotNull List<@NotNull Component> pages) {
|
||||||
this.pages = pages;
|
this.pages = new ArrayList<>(pages);
|
||||||
|
|
||||||
handleCollection(pages, "pages", nbt, () -> {
|
handleCollection(pages, "pages", () -> {
|
||||||
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
||||||
for (Component page : pages) {
|
for (Component page : pages) {
|
||||||
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));
|
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));
|
||||||
|
@ -104,10 +104,7 @@ public class BlockPlacementListener {
|
|||||||
//Send a block change with AIR as block to keep the client in sync,
|
//Send a block change with AIR as block to keep the client in sync,
|
||||||
//using refreshChunk results in the client not being in sync
|
//using refreshChunk results in the client not being in sync
|
||||||
//after rapid invalid block placements
|
//after rapid invalid block placements
|
||||||
BlockChangePacket blockChangePacket = new BlockChangePacket();
|
player.getPlayerConnection().sendPacket(new BlockChangePacket(blockPosition, Block.AIR.getBlockId()));
|
||||||
blockChangePacket.blockPosition = blockPosition;
|
|
||||||
blockChangePacket.blockStateId = Block.AIR.getBlockId();
|
|
||||||
player.getPlayerConnection().sendPacket(blockChangePacket);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -263,13 +263,6 @@ public class PlayerDiggingListener {
|
|||||||
*/
|
*/
|
||||||
private static void sendAcknowledgePacket(@NotNull Player player, @NotNull BlockPosition blockPosition, int blockStateId,
|
private static void sendAcknowledgePacket(@NotNull Player player, @NotNull BlockPosition blockPosition, int blockStateId,
|
||||||
@NotNull ClientPlayerDiggingPacket.Status status, boolean success) {
|
@NotNull ClientPlayerDiggingPacket.Status status, boolean success) {
|
||||||
AcknowledgePlayerDiggingPacket acknowledgePlayerDiggingPacket = new AcknowledgePlayerDiggingPacket();
|
player.getPlayerConnection().sendPacket(new AcknowledgePlayerDiggingPacket(blockPosition, blockStateId, status, success));
|
||||||
acknowledgePlayerDiggingPacket.blockPosition = blockPosition;
|
|
||||||
acknowledgePlayerDiggingPacket.blockStateId = blockStateId;
|
|
||||||
acknowledgePlayerDiggingPacket.status = status;
|
|
||||||
acknowledgePlayerDiggingPacket.successful = success;
|
|
||||||
|
|
||||||
player.getPlayerConnection().sendPacket(acknowledgePlayerDiggingPacket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,6 @@ import io.netty.channel.nio.NioEventLoopGroup;
|
|||||||
import io.netty.channel.socket.ServerSocketChannel;
|
import io.netty.channel.socket.ServerSocketChannel;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
import io.netty.incubator.channel.uring.IOUring;
|
|
||||||
import io.netty.incubator.channel.uring.IOUringEventLoopGroup;
|
|
||||||
import io.netty.incubator.channel.uring.IOUringServerSocketChannel;
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.network.PacketProcessor;
|
import net.minestom.server.network.PacketProcessor;
|
||||||
import net.minestom.server.network.netty.channel.ClientChannel;
|
import net.minestom.server.network.netty.channel.ClientChannel;
|
||||||
@ -82,14 +79,7 @@ public final class NettyServer {
|
|||||||
|
|
||||||
// Find boss/worker event group
|
// Find boss/worker event group
|
||||||
{
|
{
|
||||||
if (IOUring.isAvailable()) {
|
if (Epoll.isAvailable()) {
|
||||||
boss = new IOUringEventLoopGroup(2);
|
|
||||||
worker = new IOUringEventLoopGroup(workerThreadCount);
|
|
||||||
|
|
||||||
channel = IOUringServerSocketChannel.class;
|
|
||||||
|
|
||||||
LOGGER.info("Using io_uring");
|
|
||||||
} else if (Epoll.isAvailable()) {
|
|
||||||
boss = new EpollEventLoopGroup(2);
|
boss = new EpollEventLoopGroup(2);
|
||||||
worker = new EpollEventLoopGroup(workerThreadCount);
|
worker = new EpollEventLoopGroup(workerThreadCount);
|
||||||
|
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
package net.minestom.server.network.netty.codec;
|
package net.minestom.server.network.netty.codec;
|
||||||
|
|
||||||
import com.velocitypowered.natives.compression.VelocityCompressor;
|
|
||||||
import com.velocitypowered.natives.util.MoreByteBufUtils;
|
|
||||||
import com.velocitypowered.natives.util.Natives;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageCodec;
|
import io.netty.handler.codec.ByteToMessageCodec;
|
||||||
import io.netty.handler.codec.DecoderException;
|
import io.netty.handler.codec.DecoderException;
|
||||||
@ -27,6 +25,8 @@ import net.minestom.server.utils.PacketUtils;
|
|||||||
import net.minestom.server.utils.Utils;
|
import net.minestom.server.utils.Utils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
|
||||||
public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
||||||
|
|
||||||
@ -34,7 +34,8 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
|||||||
|
|
||||||
private final int threshold;
|
private final int threshold;
|
||||||
|
|
||||||
private final VelocityCompressor compressor = Natives.compress.get().create(4);
|
private final Deflater deflater = new Deflater();
|
||||||
|
private final Inflater inflater = new Inflater();
|
||||||
|
|
||||||
public PacketCompressor(int threshold) {
|
public PacketCompressor(int threshold) {
|
||||||
this.threshold = threshold;
|
this.threshold = threshold;
|
||||||
@ -42,7 +43,7 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
|
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
|
||||||
PacketUtils.compressBuffer(compressor, from, to);
|
PacketUtils.compressBuffer(deflater, from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -61,19 +62,17 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
|||||||
throw new DecoderException("Badly compressed packet - size of " + claimedUncompressedSize + " is larger than protocol maximum of " + MAX_SIZE);
|
throw new DecoderException("Badly compressed packet - size of " + claimedUncompressedSize + " is larger than protocol maximum of " + MAX_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO optimize to do not initialize arrays each time
|
||||||
|
|
||||||
ByteBuf compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, in);
|
byte[] input = new byte[in.readableBytes()];
|
||||||
ByteBuf uncompressed = MoreByteBufUtils.preferredBuffer(ctx.alloc(), compressor, claimedUncompressedSize);
|
in.readBytes(input);
|
||||||
try {
|
|
||||||
compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
|
inflater.setInput(input);
|
||||||
out.add(uncompressed);
|
byte[] output = new byte[claimedUncompressedSize];
|
||||||
in.clear();
|
inflater.inflate(output);
|
||||||
} catch (Exception e) {
|
inflater.reset();
|
||||||
uncompressed.release();
|
|
||||||
throw e;
|
out.add(Unpooled.wrappedBuffer(output));
|
||||||
} finally {
|
|
||||||
compatibleIn.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,22 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
public class AcknowledgePlayerDiggingPacket implements ServerPacket {
|
public class AcknowledgePlayerDiggingPacket implements ServerPacket {
|
||||||
|
|
||||||
public BlockPosition blockPosition = new BlockPosition(0,0,0);
|
public BlockPosition blockPosition;
|
||||||
public int blockStateId;
|
public int blockStateId;
|
||||||
public ClientPlayerDiggingPacket.Status status = ClientPlayerDiggingPacket.Status.STARTED_DIGGING;
|
public ClientPlayerDiggingPacket.Status status;
|
||||||
public boolean successful;
|
public boolean successful;
|
||||||
|
|
||||||
public AcknowledgePlayerDiggingPacket() {}
|
public AcknowledgePlayerDiggingPacket(@NotNull BlockPosition blockPosition, int blockStateId,
|
||||||
|
@NotNull ClientPlayerDiggingPacket.Status status, boolean success) {
|
||||||
|
this.blockPosition = blockPosition;
|
||||||
|
this.blockStateId = blockStateId;
|
||||||
|
this.status = status;
|
||||||
|
this.successful = success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AcknowledgePlayerDiggingPacket() {
|
||||||
|
this(new BlockPosition(0, 0, 0), 0, ClientPlayerDiggingPacket.Status.STARTED_DIGGING, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(@NotNull BinaryWriter writer) {
|
public void write(@NotNull BinaryWriter writer) {
|
||||||
|
@ -9,13 +9,14 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
public class ActionBarPacket implements ServerPacket {
|
public class ActionBarPacket implements ServerPacket {
|
||||||
|
|
||||||
public Component actionBarText = Component.empty();
|
public Component actionBarText;
|
||||||
|
|
||||||
public ActionBarPacket() {
|
public ActionBarPacket(@NotNull Component actionBarText) {
|
||||||
|
this.actionBarText = actionBarText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionBarPacket(Component actionBarText) {
|
public ActionBarPacket() {
|
||||||
this.actionBarText = actionBarText;
|
this(Component.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,17 +1,30 @@
|
|||||||
package net.minestom.server.network.packet.server.play;
|
package net.minestom.server.network.packet.server.play;
|
||||||
|
|
||||||
|
import net.minestom.server.entity.Entity;
|
||||||
import net.minestom.server.network.packet.server.ServerPacket;
|
import net.minestom.server.network.packet.server.ServerPacket;
|
||||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||||
import net.minestom.server.utils.binary.BinaryReader;
|
import net.minestom.server.utils.binary.BinaryReader;
|
||||||
import net.minestom.server.utils.binary.BinaryWriter;
|
import net.minestom.server.utils.binary.BinaryWriter;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class AttachEntityPacket implements ServerPacket {
|
public class AttachEntityPacket implements ServerPacket {
|
||||||
|
|
||||||
public int attachedEntityId;
|
public int attachedEntityId;
|
||||||
public int holdingEntityId; // Or -1 to detach
|
public int holdingEntityId; // Or -1 to detach
|
||||||
|
|
||||||
public AttachEntityPacket() {}
|
public AttachEntityPacket(int attachedEntityId, int holdingEntityId) {
|
||||||
|
this.attachedEntityId = attachedEntityId;
|
||||||
|
this.holdingEntityId = holdingEntityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachEntityPacket(@NotNull Entity attachedEntity, @Nullable Entity holdingEntity) {
|
||||||
|
this(attachedEntity.getEntityId(), holdingEntity != null ? holdingEntity.getEntityId() : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachEntityPacket() {
|
||||||
|
this(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(@NotNull BinaryWriter writer) {
|
public void write(@NotNull BinaryWriter writer) {
|
||||||
|
@ -12,8 +12,13 @@ public class BlockChangePacket implements ServerPacket {
|
|||||||
public BlockPosition blockPosition;
|
public BlockPosition blockPosition;
|
||||||
public int blockStateId;
|
public int blockStateId;
|
||||||
|
|
||||||
|
public BlockChangePacket(BlockPosition blockPosition, int blockStateId) {
|
||||||
|
this.blockPosition = blockPosition;
|
||||||
|
this.blockStateId = blockStateId;
|
||||||
|
}
|
||||||
|
|
||||||
public BlockChangePacket() {
|
public BlockChangePacket() {
|
||||||
blockPosition = new BlockPosition(0,0,0);
|
this(new BlockPosition(0, 0, 0), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.minestom.server.network.packet.server.play;
|
package net.minestom.server.network.packet.server.play;
|
||||||
|
|
||||||
|
import net.minestom.server.entity.Entity;
|
||||||
import net.minestom.server.network.packet.server.ServerPacket;
|
import net.minestom.server.network.packet.server.ServerPacket;
|
||||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||||
import net.minestom.server.utils.binary.BinaryReader;
|
import net.minestom.server.utils.binary.BinaryReader;
|
||||||
@ -10,7 +11,17 @@ public class CameraPacket implements ServerPacket {
|
|||||||
|
|
||||||
public int cameraId;
|
public int cameraId;
|
||||||
|
|
||||||
public CameraPacket() {}
|
public CameraPacket(int cameraId) {
|
||||||
|
this.cameraId = cameraId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CameraPacket(@NotNull Entity camera) {
|
||||||
|
this(camera.getEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CameraPacket() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(@NotNull BinaryWriter writer) {
|
public void write(@NotNull BinaryWriter writer) {
|
||||||
|
@ -26,18 +26,16 @@ public class ChatMessagePacket implements ComponentHoldingServerPacket {
|
|||||||
public ChatPosition position;
|
public ChatPosition position;
|
||||||
public UUID uuid;
|
public UUID uuid;
|
||||||
|
|
||||||
public ChatMessagePacket() {
|
|
||||||
this.message = Component.empty();
|
|
||||||
this.position = ChatPosition.SYSTEM_MESSAGE;
|
|
||||||
this.uuid = NULL_UUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChatMessagePacket(@NotNull Component message, @NotNull ChatPosition position, @Nullable UUID uuid) {
|
public ChatMessagePacket(@NotNull Component message, @NotNull ChatPosition position, @Nullable UUID uuid) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.uuid = Objects.requireNonNullElse(uuid, NULL_UUID);
|
this.uuid = Objects.requireNonNullElse(uuid, NULL_UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChatMessagePacket() {
|
||||||
|
this(Component.empty(), ChatPosition.SYSTEM_MESSAGE, NULL_UUID);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(@NotNull BinaryWriter writer) {
|
public void write(@NotNull BinaryWriter writer) {
|
||||||
writer.writeComponent(message);
|
writer.writeComponent(message);
|
||||||
|
@ -13,7 +13,8 @@ public class ExplosionPacket implements ServerPacket {
|
|||||||
public byte[] records = new byte[0];
|
public byte[] records = new byte[0];
|
||||||
public float playerMotionX, playerMotionY, playerMotionZ;
|
public float playerMotionX, playerMotionY, playerMotionZ;
|
||||||
|
|
||||||
public ExplosionPacket() {}
|
public ExplosionPacket() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(@NotNull BinaryWriter writer) {
|
public void write(@NotNull BinaryWriter writer) {
|
||||||
@ -21,7 +22,7 @@ public class ExplosionPacket implements ServerPacket {
|
|||||||
writer.writeFloat(y);
|
writer.writeFloat(y);
|
||||||
writer.writeFloat(z);
|
writer.writeFloat(z);
|
||||||
writer.writeFloat(radius);
|
writer.writeFloat(radius);
|
||||||
writer.writeInt(records.length/3); // each record is 3 bytes long
|
writer.writeVarInt(records.length / 3); // each record is 3 bytes long
|
||||||
for (byte record : records)
|
for (byte record : records)
|
||||||
writer.writeByte(record);
|
writer.writeByte(record);
|
||||||
writer.writeFloat(playerMotionX);
|
writer.writeFloat(playerMotionX);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.scoreboard;
|
package net.minestom.server.scoreboard;
|
||||||
|
|
||||||
import com.google.common.collect.MapMaker;
|
|
||||||
import net.kyori.adventure.identity.Identity;
|
import net.kyori.adventure.identity.Identity;
|
||||||
import net.kyori.adventure.pointer.Pointers;
|
import net.kyori.adventure.pointer.Pointers;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
@ -22,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,7 +72,7 @@ public class Team implements PacketGroupingAudience {
|
|||||||
*/
|
*/
|
||||||
private Component suffix;
|
private Component suffix;
|
||||||
|
|
||||||
private final Set<Player> playerMembers = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
|
private final Set<Player> playerMembers = ConcurrentHashMap.newKeySet();
|
||||||
private boolean isPlayerMembersUpToDate;
|
private boolean isPlayerMembersUpToDate;
|
||||||
|
|
||||||
// Adventure
|
// Adventure
|
||||||
|
@ -6,7 +6,11 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.NBTException;
|
||||||
|
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@ -21,29 +25,68 @@ import java.util.function.Supplier;
|
|||||||
@ApiStatus.NonExtendable
|
@ApiStatus.NonExtendable
|
||||||
public class Tag<T> {
|
public class Tag<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the snbt of the tag holder.
|
||||||
|
* <p>
|
||||||
|
* Writing will override all tags. Proceed with caution.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public static final Tag<String> SNBT = new Tag<>(null, NBTCompound::toSNBT, (original, snbt) -> {
|
||||||
|
try {
|
||||||
|
final var updated = new SNBTParser(new StringReader(snbt)).parse();
|
||||||
|
if (!(updated instanceof NBTCompound))
|
||||||
|
throw new IllegalArgumentException("'" + snbt + "' is not a compound!");
|
||||||
|
NBTCompound updatedCompound = (NBTCompound) updated;
|
||||||
|
original.clear();
|
||||||
|
updatedCompound.getKeys().forEach(s ->
|
||||||
|
original.set(s, Objects.requireNonNull(updatedCompound.get(s))));
|
||||||
|
} catch (NBTException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the complete tag holder compound.
|
||||||
|
* <p>
|
||||||
|
* Writing will override all tags. Proceed with caution.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public static final Tag<NBTCompound> NBT = new Tag<>(null, NBTCompound::deepClone, (original, updated) -> {
|
||||||
|
original.clear();
|
||||||
|
updated.getKeys().forEach(s -> original.set(s, Objects.requireNonNull(updated.get(s))));
|
||||||
|
}, null);
|
||||||
|
|
||||||
private final String key;
|
private final String key;
|
||||||
private final Function<NBTCompound, T> readFunction;
|
private final Function<NBTCompound, T> readFunction;
|
||||||
private final BiConsumer<NBTCompound, T> writeConsumer;
|
private final BiConsumer<NBTCompound, T> writeConsumer;
|
||||||
|
|
||||||
private final Supplier<T> defaultValue;
|
private final Supplier<T> defaultValue;
|
||||||
|
|
||||||
protected Tag(@NotNull String key,
|
protected Tag(@Nullable String key,
|
||||||
@NotNull Function<NBTCompound, T> readFunction,
|
@NotNull Function<NBTCompound, T> readFunction,
|
||||||
@NotNull BiConsumer<NBTCompound, T> writeConsumer,
|
@Nullable BiConsumer<NBTCompound, T> writeConsumer,
|
||||||
@Nullable Supplier<T> defaultValue) {
|
@Nullable Supplier<T> defaultValue) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.readFunction = readFunction;
|
this.readFunction = readFunction;
|
||||||
this.writeConsumer = writeConsumer;
|
this.writeConsumer = Objects.requireNonNullElse(writeConsumer, (compound, t) -> {
|
||||||
|
});
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Tag(@NotNull String key,
|
protected Tag(@Nullable String key,
|
||||||
@NotNull Function<NBTCompound, T> readFunction,
|
@NotNull Function<NBTCompound, T> readFunction,
|
||||||
@NotNull BiConsumer<NBTCompound, T> writeConsumer) {
|
@Nullable BiConsumer<NBTCompound, T> writeConsumer) {
|
||||||
this(key, readFunction, writeConsumer, null);
|
this(key, readFunction, writeConsumer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull String getKey() {
|
/**
|
||||||
|
* Returns the key used to navigate inside the holder nbt.
|
||||||
|
* <p>
|
||||||
|
* Can be null if unused (e.g. {@link #View(TagSerializer)}, {@link #SNBT} and {@link #NBT}).
|
||||||
|
*
|
||||||
|
* @return the tag key
|
||||||
|
*/
|
||||||
|
public @Nullable String getKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +103,7 @@ public class Tag<T> {
|
|||||||
@Contract(value = "_, _ -> new", pure = true)
|
@Contract(value = "_, _ -> new", pure = true)
|
||||||
public <R> Tag<R> map(@NotNull Function<T, R> readMap,
|
public <R> Tag<R> map(@NotNull Function<T, R> readMap,
|
||||||
@NotNull Function<R, T> writeMap) {
|
@NotNull Function<R, T> writeMap) {
|
||||||
return new Tag<R>(key,
|
return new Tag<>(key,
|
||||||
// Read
|
// Read
|
||||||
nbtCompound -> {
|
nbtCompound -> {
|
||||||
final var old = readFunction.apply(nbtCompound);
|
final var old = readFunction.apply(nbtCompound);
|
||||||
@ -85,22 +128,26 @@ public class Tag<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable T read(@NotNull NBTCompound nbtCompound) {
|
public @Nullable T read(@NotNull NBTCompound nbtCompound) {
|
||||||
if (nbtCompound.containsKey(key)) {
|
T result = readFunction.apply(nbtCompound);
|
||||||
return readFunction.apply(nbtCompound);
|
if (result == null) {
|
||||||
} else {
|
|
||||||
final var supplier = defaultValue;
|
final var supplier = defaultValue;
|
||||||
return supplier != null ? supplier.get() : null;
|
result = supplier != null ? supplier.get() : null;
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(@NotNull NBTCompound nbtCompound, @Nullable T value) {
|
public void write(@NotNull NBTCompound nbtCompound, @Nullable T value) {
|
||||||
if (value != null) {
|
if (key == null || value != null) {
|
||||||
this.writeConsumer.accept(nbtCompound, value);
|
this.writeConsumer.accept(nbtCompound, value);
|
||||||
} else {
|
} else {
|
||||||
nbtCompound.removeTag(key);
|
nbtCompound.removeTag(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeUnsafe(@NotNull NBTCompound nbtCompound, @Nullable Object value) {
|
||||||
|
write(nbtCompound, (T) value);
|
||||||
|
}
|
||||||
|
|
||||||
public static @NotNull Tag<Byte> Byte(@NotNull String key) {
|
public static @NotNull Tag<Byte> Byte(@NotNull String key) {
|
||||||
return new Tag<>(key,
|
return new Tag<>(key,
|
||||||
nbtCompound -> nbtCompound.getByte(key),
|
nbtCompound -> nbtCompound.getByte(key),
|
||||||
@ -149,17 +196,15 @@ public class Tag<T> {
|
|||||||
(nbtCompound, value) -> nbtCompound.setString(key, value));
|
(nbtCompound, value) -> nbtCompound.setString(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull Tag<NBT> NBT(@NotNull String key) {
|
public static <T extends NBT> @NotNull Tag<T> NBT(@NotNull String key) {
|
||||||
return new Tag<>(key,
|
return new Tag<>(key,
|
||||||
nbt -> {
|
nbt -> {
|
||||||
var currentNBT = nbt.get(key);
|
final var currentNBT = nbt.get(key);
|
||||||
|
|
||||||
// Avoid a NPE when cloning a null variable.
|
// Avoid a NPE when cloning a null variable.
|
||||||
if (currentNBT == null) {
|
if (currentNBT == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return (T) currentNBT.deepClone();
|
||||||
return currentNBT.deepClone();
|
|
||||||
},
|
},
|
||||||
((nbt, value) -> nbt.set(key, value.deepClone())));
|
((nbt, value) -> nbt.set(key, value.deepClone())));
|
||||||
}
|
}
|
||||||
@ -176,7 +221,15 @@ public class Tag<T> {
|
|||||||
(nbtCompound, value) -> nbtCompound.setLongArray(key, value));
|
(nbtCompound, value) -> nbtCompound.setLongArray(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> @NotNull Tag<T> Custom(@NotNull String key, @NotNull TagSerializer<T> serializer) {
|
/**
|
||||||
|
* Create a wrapper around a compound.
|
||||||
|
*
|
||||||
|
* @param key the tag key
|
||||||
|
* @param serializer the tag serializer
|
||||||
|
* @param <T> the tag type
|
||||||
|
* @return the created tag
|
||||||
|
*/
|
||||||
|
public static <T> @NotNull Tag<T> Structure(@NotNull String key, @NotNull TagSerializer<T> serializer) {
|
||||||
return new Tag<>(key,
|
return new Tag<>(key,
|
||||||
nbtCompound -> {
|
nbtCompound -> {
|
||||||
final var compound = nbtCompound.getCompound(key);
|
final var compound = nbtCompound.getCompound(key);
|
||||||
@ -194,4 +247,18 @@ public class Tag<T> {
|
|||||||
serializer.write(TagWritable.fromCompound(compound), value);
|
serializer.write(TagWritable.fromCompound(compound), value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> @NotNull Tag<T> View(@NotNull TagSerializer<T> serializer) {
|
||||||
|
return new Tag<>(null,
|
||||||
|
nbtCompound -> serializer.read(TagReadable.fromCompound(nbtCompound)),
|
||||||
|
(nbtCompound, value) -> serializer.write(TagWritable.fromCompound(nbtCompound), value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #Structure(String, TagSerializer)} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static <T> @NotNull Tag<T> Custom(@NotNull String key, @NotNull TagSerializer<T> serializer) {
|
||||||
|
return Structure(key, serializer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.minestom.server.tag;
|
package net.minestom.server.tag;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an element which can read and write {@link Tag tags}.
|
* Represents an element which can read and write {@link Tag tags}.
|
||||||
*/
|
*/
|
||||||
@Beta
|
@ApiStatus.Experimental
|
||||||
public interface TagHandler extends TagReadable, TagWritable {
|
public interface TagHandler extends TagReadable, TagWritable {
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ public interface TagReadable {
|
|||||||
* @param tag the tag to check
|
* @param tag the tag to check
|
||||||
* @return true if the tag is present, false otherwise
|
* @return true if the tag is present, false otherwise
|
||||||
*/
|
*/
|
||||||
boolean hasTag(@NotNull Tag<?> tag);
|
default boolean hasTag(@NotNull Tag<?> tag) {
|
||||||
|
return getTag(tag) != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an nbt compound to a tag reader.
|
* Converts an nbt compound to a tag reader.
|
||||||
@ -38,11 +40,6 @@ public interface TagReadable {
|
|||||||
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||||
return tag.read(compound);
|
return tag.read(compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasTag(@NotNull Tag<?> tag) {
|
|
||||||
return compound.containsKey(tag.getKey());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface used to create custom types compatible with {@link Tag#Custom(String, TagSerializer)}.
|
* Interface used to create custom {@link Tag tags}.
|
||||||
*
|
*
|
||||||
* @param <T> the type to serialize
|
* @param <T> the type to serialize
|
||||||
*/
|
*/
|
||||||
@ -14,7 +14,7 @@ public interface TagSerializer<T> {
|
|||||||
* Reads the custom tag from a {@link TagReadable}.
|
* Reads the custom tag from a {@link TagReadable}.
|
||||||
*
|
*
|
||||||
* @param reader the reader
|
* @param reader the reader
|
||||||
* @return the deserialized value
|
* @return the deserialized value, null if invalid
|
||||||
*/
|
*/
|
||||||
@Nullable T read(@NotNull TagReadable reader);
|
@Nullable T read(@NotNull TagReadable reader);
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ public interface TagSerializer<T> {
|
|||||||
* Writes the custom tag to a {@link TagWritable}.
|
* Writes the custom tag to a {@link TagWritable}.
|
||||||
*
|
*
|
||||||
* @param writer the writer
|
* @param writer the writer
|
||||||
* @param value the value to serialize
|
* @param value the value to serialize, null to remove
|
||||||
*/
|
*/
|
||||||
void write(@NotNull TagWritable writer, @NotNull T value);
|
void write(@NotNull TagWritable writer, @Nullable T value);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ public interface TagWritable {
|
|||||||
*/
|
*/
|
||||||
<T> void setTag(@NotNull Tag<T> tag, @Nullable T value);
|
<T> void setTag(@NotNull Tag<T> tag, @Nullable T value);
|
||||||
|
|
||||||
|
default void removeTag(@NotNull Tag<?> tag) {
|
||||||
|
setTag(tag, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an nbt compound to a tag writer.
|
* Converts an nbt compound to a tag writer.
|
||||||
*
|
*
|
||||||
|
@ -47,10 +47,6 @@ public final class MathUtils {
|
|||||||
return Direction.HORIZONTAL[directionIndex];
|
return Direction.HORIZONTAL[directionIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float clampFloat(float t, float a, float b) {
|
|
||||||
return Math.max(a, Math.min(t, b));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isBetween(byte number, byte min, byte max) {
|
public static boolean isBetween(byte number, byte min, byte max) {
|
||||||
return number >= min && number <= max;
|
return number >= min && number <= max;
|
||||||
}
|
}
|
||||||
@ -84,11 +80,15 @@ public final class MathUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int clamp(int value, int min, int max) {
|
public static int clamp(int value, int min, int max) {
|
||||||
if (value < min) {
|
return Math.min(Math.max(value, min), max);
|
||||||
return min;
|
|
||||||
} else {
|
|
||||||
return Math.min(value, max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float clamp(float value, float min, float max) {
|
||||||
|
return Math.min(Math.max(value, min), max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double clamp(double value, double min, double max) {
|
||||||
|
return Math.min(Math.max(value, min), max);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double mod(final double a, final double b) {
|
public static double mod(final double a, final double b) {
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package net.minestom.server.utils;
|
package net.minestom.server.utils;
|
||||||
|
|
||||||
import com.velocitypowered.natives.compression.VelocityCompressor;
|
|
||||||
import com.velocitypowered.natives.util.Natives;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.audience.Audience;
|
import net.kyori.adventure.audience.Audience;
|
||||||
import net.kyori.adventure.audience.ForwardingAudience;
|
import net.kyori.adventure.audience.ForwardingAudience;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.adventure.AdventureSerializer;
|
|
||||||
import net.minestom.server.adventure.MinestomAdventure;
|
import net.minestom.server.adventure.MinestomAdventure;
|
||||||
import net.minestom.server.adventure.audience.PacketGroupingAudience;
|
import net.minestom.server.adventure.audience.PacketGroupingAudience;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
@ -21,8 +18,9 @@ import net.minestom.server.utils.callback.validator.PlayerValidator;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.Deflater;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utils class for packets. Including writing a {@link ServerPacket} into a {@link ByteBuf}
|
* Utils class for packets. Including writing a {@link ServerPacket} into a {@link ByteBuf}
|
||||||
@ -31,7 +29,7 @@ import java.util.zip.DataFormatException;
|
|||||||
public final class PacketUtils {
|
public final class PacketUtils {
|
||||||
|
|
||||||
private static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
|
private static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
|
||||||
private static final ThreadLocal<VelocityCompressor> COMPRESSOR = ThreadLocal.withInitial(() -> Natives.compress.get().create(4));
|
private static final ThreadLocal<Deflater> COMPRESSOR = ThreadLocal.withInitial(Deflater::new);
|
||||||
|
|
||||||
private PacketUtils() {
|
private PacketUtils() {
|
||||||
}
|
}
|
||||||
@ -189,29 +187,37 @@ public final class PacketUtils {
|
|||||||
* <p>
|
* <p>
|
||||||
* {@code packetBuffer} needs to be the packet content without any header (if you want to use it to write a Minecraft packet).
|
* {@code packetBuffer} needs to be the packet content without any header (if you want to use it to write a Minecraft packet).
|
||||||
*
|
*
|
||||||
* @param compressor the deflater for zlib compression
|
* @param deflater the deflater for zlib compression
|
||||||
* @param packetBuffer the buffer containing all the packet fields
|
* @param packetBuffer the buffer containing all the packet fields
|
||||||
* @param compressionTarget the buffer which will receive the compressed version of {@code packetBuffer}
|
* @param compressionTarget the buffer which will receive the compressed version of {@code packetBuffer}
|
||||||
*/
|
*/
|
||||||
public static void compressBuffer(@NotNull VelocityCompressor compressor, @NotNull ByteBuf packetBuffer, @NotNull ByteBuf compressionTarget) {
|
public static void compressBuffer(@NotNull Deflater deflater, @NotNull ByteBuf packetBuffer, @NotNull ByteBuf compressionTarget) {
|
||||||
final int packetLength = packetBuffer.readableBytes();
|
final int packetLength = packetBuffer.readableBytes();
|
||||||
final boolean compression = packetLength > MinecraftServer.getCompressionThreshold();
|
final boolean compression = packetLength > MinecraftServer.getCompressionThreshold();
|
||||||
Utils.writeVarInt(compressionTarget, compression ? packetLength : 0);
|
Utils.writeVarInt(compressionTarget, compression ? packetLength : 0);
|
||||||
if (compression) {
|
if (compression) {
|
||||||
compress(compressor, packetBuffer, compressionTarget);
|
compress(deflater, packetBuffer, compressionTarget);
|
||||||
} else {
|
} else {
|
||||||
compressionTarget.writeBytes(packetBuffer);
|
compressionTarget.writeBytes(packetBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void compress(@NotNull VelocityCompressor compressor, @NotNull ByteBuf uncompressed, @NotNull ByteBuf compressed) {
|
private static void compress(@NotNull Deflater deflater, @NotNull ByteBuf uncompressed, @NotNull ByteBuf compressed) {
|
||||||
try {
|
deflater.setInput(uncompressed.nioBuffer());
|
||||||
compressor.deflate(uncompressed, compressed);
|
deflater.finish();
|
||||||
} catch (DataFormatException e) {
|
|
||||||
e.printStackTrace();
|
while (!deflater.finished()) {
|
||||||
|
ByteBuffer nioBuffer = compressed.nioBuffer(compressed.writerIndex(), compressed.writableBytes());
|
||||||
|
compressed.writerIndex(deflater.deflate(nioBuffer) + compressed.writerIndex());
|
||||||
|
|
||||||
|
if (compressed.writableBytes() == 0) {
|
||||||
|
compressed.ensureWritable(8192);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deflater.reset();
|
||||||
|
}
|
||||||
|
|
||||||
public static void writeFramedPacket(@NotNull ByteBuf buffer,
|
public static void writeFramedPacket(@NotNull ByteBuf buffer,
|
||||||
@NotNull ServerPacket serverPacket) {
|
@NotNull ServerPacket serverPacket) {
|
||||||
final int compressionThreshold = MinecraftServer.getCompressionThreshold();
|
final int compressionThreshold = MinecraftServer.getCompressionThreshold();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.utils;
|
package net.minestom.server.utils;
|
||||||
|
|
||||||
import com.google.common.primitives.Doubles;
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.utils.clone.PublicCloneable;
|
import net.minestom.server.utils.clone.PublicCloneable;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -167,7 +166,7 @@ public class Vector implements PublicCloneable<Vector> {
|
|||||||
* @return angle in radians
|
* @return angle in radians
|
||||||
*/
|
*/
|
||||||
public float angle(@NotNull Vector other) {
|
public float angle(@NotNull Vector other) {
|
||||||
double dot = Doubles.constrainToRange(dot(other) / (length() * other.length()), -1.0, 1.0);
|
double dot = MathUtils.clamp(dot(other) / (length() * other.length()), -1.0, 1.0);
|
||||||
|
|
||||||
return (float) Math.acos(dot);
|
return (float) Math.acos(dot);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.minestom.server.utils.cache;
|
package net.minestom.server.utils.cache;
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import com.google.common.cache.RemovalListener;
|
import com.github.benmanes.caffeine.cache.RemovalListener;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ public class TemporaryCache<T> {
|
|||||||
* @param duration the time before considering an object unused
|
* @param duration the time before considering an object unused
|
||||||
*/
|
*/
|
||||||
public TemporaryCache(long duration, TimeUnit timeUnit, RemovalListener<UUID, T> removalListener) {
|
public TemporaryCache(long duration, TimeUnit timeUnit, RemovalListener<UUID, T> removalListener) {
|
||||||
this.cache = CacheBuilder.newBuilder()
|
this.cache = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(duration, timeUnit)
|
.expireAfterWrite(duration, timeUnit)
|
||||||
.removalListener(removalListener)
|
.removalListener(removalListener)
|
||||||
.build();
|
.build();
|
||||||
|
@ -6,8 +6,10 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
public class TemporaryPacketCache extends TemporaryCache<TimedBuffer> {
|
public class TemporaryPacketCache extends TemporaryCache<TimedBuffer> {
|
||||||
public TemporaryPacketCache(long duration, TimeUnit timeUnit) {
|
public TemporaryPacketCache(long duration, TimeUnit timeUnit) {
|
||||||
super(duration, timeUnit, notification -> {
|
super(duration, timeUnit, (key, value, cause) -> {
|
||||||
final ByteBuf buffer = notification.getValue().getBuffer();
|
if (value == null)
|
||||||
|
return;
|
||||||
|
final ByteBuf buffer = value.getBuffer();
|
||||||
synchronized (buffer) {
|
synchronized (buffer) {
|
||||||
buffer.release();
|
buffer.release();
|
||||||
}
|
}
|
||||||
|
@ -28,4 +28,17 @@ public class RelativeBlockPosition extends RelativeLocation<BlockPosition> {
|
|||||||
|
|
||||||
return new BlockPosition(x, y, z);
|
return new BlockPosition(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockPosition fromView(@Nullable Position position) {
|
||||||
|
if (!relativeX && !relativeY && !relativeZ) {
|
||||||
|
return location.clone();
|
||||||
|
}
|
||||||
|
final Position entityPosition = position != null ? position : new Position();
|
||||||
|
|
||||||
|
final int x = location.getX() + (relativeX ? (int) entityPosition.getYaw() : 0);
|
||||||
|
final int z = location.getZ() + (relativeZ ? (int) entityPosition.getPitch() : 0);
|
||||||
|
|
||||||
|
return new BlockPosition(x, 0, z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package net.minestom.server.utils.location;
|
|||||||
|
|
||||||
import net.minestom.server.entity.Entity;
|
import net.minestom.server.entity.Entity;
|
||||||
import net.minestom.server.utils.Position;
|
import net.minestom.server.utils.Position;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@ -22,19 +23,6 @@ public abstract class RelativeLocation<T> {
|
|||||||
this.relativeZ = relativeZ;
|
this.relativeZ = relativeZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location based on the relative fields and {@code entity}.
|
|
||||||
*
|
|
||||||
* @param entity the entity to get the relative position from
|
|
||||||
* @return the location
|
|
||||||
*/
|
|
||||||
public T from(@Nullable Entity entity) {
|
|
||||||
|
|
||||||
final Position entityPosition = entity != null ? entity.getPosition() : new Position();
|
|
||||||
|
|
||||||
return from(entityPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location based on the relative fields and {@code position}.
|
* Gets the location based on the relative fields and {@code position}.
|
||||||
*
|
*
|
||||||
@ -43,6 +31,26 @@ public abstract class RelativeLocation<T> {
|
|||||||
*/
|
*/
|
||||||
public abstract T from(@Nullable Position position);
|
public abstract T from(@Nullable Position position);
|
||||||
|
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public abstract T fromView(@Nullable Position position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location based on the relative fields and {@code entity}.
|
||||||
|
*
|
||||||
|
* @param entity the entity to get the relative position from
|
||||||
|
* @return the location
|
||||||
|
*/
|
||||||
|
public T from(@Nullable Entity entity) {
|
||||||
|
final Position entityPosition = entity != null ? entity.getPosition() : new Position();
|
||||||
|
return from(entityPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public T fromView(@Nullable Entity entity) {
|
||||||
|
final Position entityPosition = entity != null ? entity.getPosition() : new Position();
|
||||||
|
return fromView(entityPosition);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets if the 'x' field is relative.
|
* Gets if the 'x' field is relative.
|
||||||
*
|
*
|
||||||
|
@ -28,4 +28,17 @@ public class RelativeVec extends RelativeLocation<Vector> {
|
|||||||
|
|
||||||
return new Vector(x, y, z);
|
return new Vector(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector fromView(@Nullable Position position) {
|
||||||
|
if (!relativeX && !relativeY && !relativeZ) {
|
||||||
|
return location.clone();
|
||||||
|
}
|
||||||
|
final Position entityPosition = position != null ? position : new Position();
|
||||||
|
|
||||||
|
final double x = location.getX() + (relativeX ? entityPosition.getYaw() : 0);
|
||||||
|
final double z = location.getZ() + (relativeZ ? entityPosition.getPitch() : 0);
|
||||||
|
|
||||||
|
return new Vector(x, 0, z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.minestom.server.utils.mojang;
|
package net.minestom.server.utils.mojang;
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
@ -17,12 +17,12 @@ import java.util.concurrent.TimeUnit;
|
|||||||
*/
|
*/
|
||||||
public final class MojangUtils {
|
public final class MojangUtils {
|
||||||
|
|
||||||
private static final Cache<String, JsonObject> UUID_CACHE = CacheBuilder.newBuilder()
|
private static final Cache<String, JsonObject> UUID_CACHE = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(30, TimeUnit.SECONDS)
|
.expireAfterWrite(30, TimeUnit.SECONDS)
|
||||||
.softValues()
|
.softValues()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private static final Cache<String, JsonObject> USERNAME_CACHE = CacheBuilder.newBuilder()
|
private static final Cache<String, JsonObject> USERNAME_CACHE = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(30, TimeUnit.SECONDS)
|
.expireAfterWrite(30, TimeUnit.SECONDS)
|
||||||
.softValues()
|
.softValues()
|
||||||
.build();
|
.build();
|
||||||
|
@ -55,16 +55,12 @@ public class PlayerInit {
|
|||||||
.addListener(EntityAttackEvent.class, event -> {
|
.addListener(EntityAttackEvent.class, event -> {
|
||||||
final Entity source = event.getEntity();
|
final Entity source = event.getEntity();
|
||||||
final Entity entity = event.getTarget();
|
final Entity entity = event.getTarget();
|
||||||
|
|
||||||
|
entity.takeKnockback(0.4f, Math.sin(source.getPosition().getYaw() * 0.017453292), -Math.cos(source.getPosition().getYaw() * 0.017453292));
|
||||||
|
|
||||||
if (entity instanceof Player) {
|
if (entity instanceof Player) {
|
||||||
Player target = (Player) entity;
|
Player target = (Player) entity;
|
||||||
Vector velocity = source.getPosition().clone().getDirection().multiply(4);
|
|
||||||
velocity.setY(3.5f);
|
|
||||||
target.setVelocity(velocity);
|
|
||||||
target.damage(DamageType.fromEntity(source), 5);
|
target.damage(DamageType.fromEntity(source), 5);
|
||||||
} else {
|
|
||||||
Vector velocity = source.getPosition().clone().getDirection().multiply(3);
|
|
||||||
velocity.setY(3f);
|
|
||||||
entity.setVelocity(velocity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source instanceof Player) {
|
if (source instanceof Player) {
|
||||||
|
Loading…
Reference in New Issue
Block a user