mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-04 23:47:59 +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'
|
||||
url 'https://repo.spongepowered.org/maven'
|
||||
}
|
||||
maven {
|
||||
url "https://repo.velocitypowered.com/snapshots/"
|
||||
}
|
||||
}
|
||||
javadoc {
|
||||
options {
|
||||
@ -111,11 +108,10 @@ dependencies {
|
||||
testCompileOnly "org.mockito:mockito-core:2.28.2"
|
||||
|
||||
// Netty
|
||||
api 'io.netty:netty-handler:4.1.63.Final'
|
||||
api 'io.netty:netty-codec:4.1.63.Final'
|
||||
api 'io.netty:netty-transport-native-epoll:4.1.63.Final:linux-x86_64'
|
||||
api 'io.netty:netty-transport-native-kqueue:4.1.63.Final:osx-x86_64'
|
||||
api 'io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.5.Final:linux-x86_64'
|
||||
api 'io.netty:netty-handler:4.1.65.Final'
|
||||
api 'io.netty:netty-codec:4.1.65.Final'
|
||||
api 'io.netty:netty-transport-native-epoll:4.1.65.Final:linux-x86_64'
|
||||
api 'io.netty:netty-transport-native-kqueue:4.1.65.Final:osx-x86_64'
|
||||
|
||||
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
|
||||
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
|
||||
implementation 'org.fusesource.jansi:jansi:2.3.2'
|
||||
|
||||
implementation 'com.github.ben-manes.caffeine:caffeine:3.0.2'
|
||||
|
||||
// Guava 21.0+ required for Mixin
|
||||
api 'com.google.guava:guava:30.1-jre'
|
||||
|
||||
@ -153,9 +151,6 @@ dependencies {
|
||||
api "org.ow2.asm:asm-commons:${asmVersion}"
|
||||
api "org.spongepowered:mixin:${mixinVersion}"
|
||||
|
||||
// Compression
|
||||
implementation "com.velocitypowered:velocity-native:1.1.0-SNAPSHOT"
|
||||
|
||||
// Path finding
|
||||
api 'com.github.MadMartian:hydrazine-path-finding:1.6.0'
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server;
|
||||
|
||||
import com.google.common.collect.Queues;
|
||||
import net.minestom.server.acquirable.Acquirable;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.Instance;
|
||||
@ -34,8 +33,8 @@ public final class UpdateManager {
|
||||
// TODO make configurable
|
||||
private ThreadProvider threadProvider = new SingleThreadProvider();
|
||||
|
||||
private final Queue<LongConsumer> tickStartCallbacks = Queues.newConcurrentLinkedQueue();
|
||||
private final Queue<LongConsumer> tickEndCallbacks = Queues.newConcurrentLinkedQueue();
|
||||
private final Queue<LongConsumer> tickStartCallbacks = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<LongConsumer> tickEndCallbacks = new ConcurrentLinkedQueue<>();
|
||||
private final List<Consumer<TickMonitor>> tickMonitors = new CopyOnWriteArrayList<>();
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server.acquirable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.thread.ThreadProvider;
|
||||
import net.minestom.server.thread.TickThread;
|
||||
@ -14,7 +13,7 @@ import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public interface Acquirable<T> {
|
||||
|
||||
/**
|
||||
|
@ -1,15 +1,15 @@
|
||||
package net.minestom.server.acquirable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import net.minestom.server.thread.TickThread;
|
||||
import net.minestom.server.utils.async.AsyncUtils;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public class AcquirableCollection<E> implements Collection<Acquirable<E>> {
|
||||
|
||||
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.message.ChatPosition;
|
||||
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.utils.PacketUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -44,6 +45,14 @@ public interface PacketGroupingAudience extends ForwardingAudience {
|
||||
*/
|
||||
@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
|
||||
default void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
|
||||
Messenger.sendMessage(this.getPlayers(), message, ChatPosition.fromMessageType(type), source.uuid());
|
||||
@ -51,28 +60,28 @@ public interface PacketGroupingAudience extends ForwardingAudience {
|
||||
|
||||
@Override
|
||||
default void sendActionBar(@NotNull Component message) {
|
||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new ActionBarPacket(message));
|
||||
sendGroupedPacket(new ActionBarPacket(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendPlayerListHeaderAndFooter(@NotNull Component header, @NotNull Component footer) {
|
||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new PlayerListHeaderAndFooterPacket(header, footer));
|
||||
sendGroupedPacket(new PlayerListHeaderAndFooterPacket(header, footer));
|
||||
}
|
||||
|
||||
@Override
|
||||
default void showTitle(@NotNull Title title) {
|
||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new SetTitleTextPacket(title.title()));
|
||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new SetTitleSubTitlePacket(title.subtitle()));
|
||||
sendGroupedPacket(new SetTitleTextPacket(title.title()));
|
||||
sendGroupedPacket(new SetTitleSubTitlePacket(title.subtitle()));
|
||||
}
|
||||
|
||||
@Override
|
||||
default void clearTitle() {
|
||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new ClearTitlesPacket());
|
||||
sendGroupedPacket(new ClearTitlesPacket());
|
||||
}
|
||||
|
||||
@Override
|
||||
default void resetTitle() {
|
||||
PacketUtils.sendGroupedPacket(this.getPlayers(), new ClearTitlesPacket(true));
|
||||
sendGroupedPacket(new ClearTitlesPacket(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -87,13 +96,13 @@ public interface PacketGroupingAudience extends ForwardingAudience {
|
||||
|
||||
@Override
|
||||
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
|
||||
default void playSound(@NotNull Sound sound, Sound.@NotNull Emitter emitter) {
|
||||
if (emitter != Sound.Emitter.self()) {
|
||||
PacketUtils.sendGroupedPacket(this.getPlayers(), AdventurePacketConvertor.createSoundPacket(sound, emitter));
|
||||
sendGroupedPacket(AdventurePacketConvertor.createSoundPacket(sound, emitter));
|
||||
} else {
|
||||
// if we're playing on self, we need to delegate to each audience member
|
||||
for (Audience audience : this.audiences()) {
|
||||
@ -104,7 +113,7 @@ public interface PacketGroupingAudience extends ForwardingAudience {
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
import io.netty.util.internal.ThreadLocalRandom;
|
||||
import net.minestom.server.utils.UniqueIdUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Represent an attribute modifier.
|
||||
|
@ -5,6 +5,7 @@ import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.chat.JsonMessage;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.permission.PermissionHandler;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@ -12,7 +13,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* <p>
|
||||
* 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.
|
||||
@ -28,7 +29,7 @@ public interface CommandSender extends PermissionHandler, Audience {
|
||||
*
|
||||
* @param messages the messages to send
|
||||
*/
|
||||
default void sendMessage(@NotNull String @NotNull[] messages) {
|
||||
default void sendMessage(@NotNull String @NotNull [] messages) {
|
||||
for (String message : messages) {
|
||||
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.
|
||||
*
|
||||
* @param text The {@link JsonMessage} to send.
|
||||
*
|
||||
* @deprecated Use {@link #sendMessage(Component)}
|
||||
* */
|
||||
*/
|
||||
@Deprecated
|
||||
default void sendMessage(@NotNull JsonMessage text) {
|
||||
this.sendMessage(text.asComponent());
|
||||
|
@ -3,9 +3,12 @@ package net.minestom.server.command;
|
||||
import net.kyori.adventure.audience.MessageType;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
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.tag.Tag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -16,10 +19,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
* Represents the console when sending a command to the server.
|
||||
*/
|
||||
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 final Set<Permission> permissions = new CopyOnWriteArraySet<>();
|
||||
private final NBTCompound nbtCompound = new NBTCompound();
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NotNull String message) {
|
||||
@ -27,7 +31,7 @@ public class ConsoleSender implements CommandSender {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
|
||||
public void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
|
||||
// we don't use the serializer here as we just need the plain text of the message
|
||||
this.sendMessage(PLAIN_SERIALIZER.serialize(message));
|
||||
}
|
||||
@ -47,4 +51,14 @@ public class ConsoleSender implements CommandSender {
|
||||
public ConsoleSender asConsole() {
|
||||
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.kyori.adventure.audience.Audience;
|
||||
import net.minestom.server.permission.Permission;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@ -19,10 +22,21 @@ import java.util.Set;
|
||||
public class ServerSender implements CommandSender {
|
||||
|
||||
private final Set<Permission> permissions = Collections.unmodifiableSet(new HashSet<>());
|
||||
private final NBTCompound nbtCompound = new NBTCompound();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Permission> getAllPermissions() {
|
||||
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;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
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.condition.CommandCondition;
|
||||
import net.minestom.server.utils.StringUtils;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@ -221,7 +221,7 @@ public class Command {
|
||||
* @param format the syntax format
|
||||
* @return the newly created {@link CommandSyntax syntaxes}.
|
||||
*/
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public @NotNull Collection<CommandSyntax> addSyntax(@NotNull CommandExecutor executor, @NotNull String 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) {
|
||||
}
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public @NotNull Set<String> getSyntaxesStrings() {
|
||||
Set<String> syntaxes = new HashSet<>();
|
||||
|
||||
@ -320,7 +320,7 @@ public class Command {
|
||||
return syntaxes;
|
||||
}
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public @NotNull String getSyntaxesTree() {
|
||||
Node commandNode = new Node();
|
||||
commandNode.names.addAll(Arrays.asList(getNames()));
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.minestom.server.command.builder;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
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 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)
|
||||
.build();
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
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.Command;
|
||||
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.suggestion.SuggestionCallback;
|
||||
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -210,8 +210,8 @@ public abstract class Argument<T> {
|
||||
/**
|
||||
* Gets the suggestion callback of the argument
|
||||
*
|
||||
* @see #setSuggestionCallback
|
||||
* @return the suggestion callback of the argument, null if it doesn't exist
|
||||
* @see #setSuggestionCallback
|
||||
*/
|
||||
@Nullable
|
||||
public SuggestionCallback getSuggestionCallback() {
|
||||
@ -247,7 +247,7 @@ public abstract class Argument<T> {
|
||||
* @param <O> The type of output expected.
|
||||
* @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) {
|
||||
return new ArgumentMap<>(this, mapper);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server.command.builder.arguments;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.builder.CommandDispatcher;
|
||||
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.network.packet.server.play.DeclareCommandsPacket;
|
||||
import net.minestom.server.utils.StringUtils;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ArgumentCommand extends Argument<CommandResult> {
|
||||
@ -69,7 +69,7 @@ public class ArgumentCommand extends Argument<CommandResult> {
|
||||
return shortcut;
|
||||
}
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public ArgumentCommand setShortcut(@NotNull String shortcut) {
|
||||
this.shortcut = shortcut;
|
||||
return this;
|
||||
|
@ -1,6 +1,5 @@
|
||||
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.registry.*;
|
||||
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.ArgumentRelativeVec3;
|
||||
import net.minestom.server.command.builder.parser.ArgumentParser;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@ -248,7 +248,7 @@ public class ArgumentType {
|
||||
* <p>
|
||||
* 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) {
|
||||
return ArgumentParser.generate(format);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
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.minecraft.*;
|
||||
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.exception.ArgumentSyntaxException;
|
||||
import net.minestom.server.utils.StringUtils;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -63,7 +63,7 @@ public class ArgumentParser {
|
||||
ARGUMENT_FUNCTION_MAP.put("relativevec2", ArgumentRelativeVec2::new);
|
||||
}
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public static @NotNull Argument<?>[] generate(@NotNull String format) {
|
||||
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.
|
||||
* <p>
|
||||
* The data will always be optional and can therefore be null.
|
||||
*
|
||||
* @deprecated switch to the Tag API instead
|
||||
*/
|
||||
@Deprecated
|
||||
public interface DataContainer {
|
||||
|
||||
/**
|
||||
@ -16,9 +19,10 @@ public interface DataContainer {
|
||||
* meaning that this will be null if no data has been defined.
|
||||
*
|
||||
* @return the {@link Data} of this container, can be null
|
||||
* @deprecated use the tag API https://wiki.minestom.com/feature/tags
|
||||
*/
|
||||
@Nullable
|
||||
Data getData();
|
||||
@Deprecated
|
||||
@Nullable Data getData();
|
||||
|
||||
/**
|
||||
* Sets the {@link Data} of this container.
|
||||
@ -27,7 +31,8 @@ public interface DataContainer {
|
||||
* on your use-case.
|
||||
*
|
||||
* @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);
|
||||
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
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.text.Component;
|
||||
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.PotionEffect;
|
||||
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.utils.BlockPosition;
|
||||
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.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -65,7 +67,7 @@ import java.util.function.UnaryOperator;
|
||||
* <p>
|
||||
* 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<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 boolean hasPhysics = true;
|
||||
|
||||
/**
|
||||
* The amount of drag applied on the Y axle.
|
||||
* <p>
|
||||
* Unit: 1/tick
|
||||
*/
|
||||
protected double gravityDragPerTick;
|
||||
/**
|
||||
* Acceleration on the Y axle due to gravity
|
||||
* <p>
|
||||
* Unit: blocks/tick
|
||||
*/
|
||||
protected double gravityAcceleration;
|
||||
protected double gravityTerminalVelocity;
|
||||
protected int gravityTickCount; // Number of tick where gravity tick was applied
|
||||
|
||||
private boolean autoViewable;
|
||||
@ -103,6 +114,7 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
protected final Set<Player> viewers = ConcurrentHashMap.newKeySet();
|
||||
private final Set<Player> unmodifiableViewers = Collections.unmodifiableSet(viewers);
|
||||
private Data data;
|
||||
private final NBTCompound nbtCompound = new NBTCompound();
|
||||
private final Set<Permission> permissions = new CopyOnWriteArraySet<>();
|
||||
|
||||
protected UUID uuid;
|
||||
@ -128,7 +140,7 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
private final List<TimedPotion> effects = new CopyOnWriteArrayList<>();
|
||||
|
||||
// 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
|
||||
private long ticks;
|
||||
@ -159,6 +171,8 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
Entity.ENTITY_BY_UUID.put(uuid, this);
|
||||
|
||||
this.eventNode = EventNode.value("entity-" + uuid, EventFilter.ENTITY, this::equals);
|
||||
|
||||
initializeDefaultGravity();
|
||||
}
|
||||
|
||||
public Entity(@NotNull EntityType entityType) {
|
||||
@ -524,13 +538,11 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
Vector newVelocityOut = new Vector();
|
||||
|
||||
// Gravity force
|
||||
final double gravityY = !hasNoGravity() ? Math.min(
|
||||
gravityDragPerTick + (gravityAcceleration * (double) gravityTickCount),
|
||||
gravityTerminalVelocity) : 0;
|
||||
final double gravityY = hasNoGravity() ? 0 : gravityAcceleration;
|
||||
|
||||
final Vector deltaPos = new Vector(
|
||||
getVelocity().getX() / tps,
|
||||
(getVelocity().getY() - gravityY) / tps,
|
||||
getVelocity().getY() / tps - gravityY,
|
||||
getVelocity().getZ() / tps
|
||||
);
|
||||
|
||||
@ -591,6 +603,8 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
|
||||
this.velocity.setX(velocity.getX() * drag);
|
||||
this.velocity.setZ(velocity.getZ() * drag);
|
||||
if (!hasNoGravity())
|
||||
this.velocity.setY(velocity.getY() * (1-gravityDragPerTick));
|
||||
|
||||
if (velocity.equals(new Vector())) {
|
||||
this.velocity.zero();
|
||||
@ -982,15 +996,6 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
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.
|
||||
*
|
||||
@ -1005,13 +1010,11 @@ public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, Da
|
||||
*
|
||||
* @param gravityDragPerTick the gravity drag per tick 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>
|
||||
*/
|
||||
public void setGravity(double gravityDragPerTick, double gravityAcceleration, double gravityTerminalVelocity) {
|
||||
public void setGravity(double gravityDragPerTick, double gravityAcceleration) {
|
||||
this.gravityDragPerTick = gravityDragPerTick;
|
||||
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);
|
||||
}
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public <T extends Entity> @NotNull Acquirable<T> getAcquirable() {
|
||||
return (Acquirable<T>) acquirable;
|
||||
}
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public <T extends Entity> @NotNull Acquirable<T> getAcquirable(@NotNull Class<T> clazz) {
|
||||
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 {
|
||||
STANDING,
|
||||
FALL_FLYING,
|
||||
|
@ -47,7 +47,6 @@ public class EntityProjectile extends Entity {
|
||||
if (getEntityMeta() instanceof ProjectileMeta) {
|
||||
((ProjectileMeta) getEntityMeta()).setShooter(this.shooter);
|
||||
}
|
||||
setGravity(0.02f, 0.04f, 1.96f);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -17,7 +17,6 @@ public class ExperienceOrb extends Entity {
|
||||
|
||||
public ExperienceOrb(short experienceCount, @NotNull Position spawnPosition) {
|
||||
super(EntityType.EXPERIENCE_ORB, spawnPosition);
|
||||
setGravity(0.02f, 0.04f, 1.96f);
|
||||
setBoundingBox(0.5f, 0.5f, 0.5f);
|
||||
//todo vanilla sets random velocity here?
|
||||
this.experienceCount = experienceCount;
|
||||
|
@ -43,7 +43,6 @@ public class ItemEntity extends Entity {
|
||||
public ItemEntity(@NotNull ItemStack itemStack, @NotNull Position spawnPosition) {
|
||||
super(EntityType.ITEM, spawnPosition);
|
||||
setItemStack(itemStack);
|
||||
setGravity(0.02f, 0.04f, 1.96f);
|
||||
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) {
|
||||
this(entityType, uuid, new Position());
|
||||
setGravity(0.02f, 0.08f, 3.92f);
|
||||
initEquipments();
|
||||
}
|
||||
|
||||
@ -104,7 +103,6 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
||||
@Deprecated
|
||||
public LivingEntity(@NotNull EntityType entityType, @NotNull UUID uuid, @NotNull Position spawnPosition) {
|
||||
super(entityType, uuid, spawnPosition);
|
||||
setGravity(0.02f, 0.08f, 3.92f);
|
||||
initEquipments();
|
||||
}
|
||||
|
||||
@ -781,4 +779,18 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
||||
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;
|
||||
|
||||
import com.google.common.collect.Queues;
|
||||
import net.kyori.adventure.audience.MessageType;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.identity.Identified;
|
||||
@ -87,6 +86,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
@ -119,7 +119,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
private final AtomicInteger teleportId = new AtomicInteger();
|
||||
private int receivedTeleportId;
|
||||
|
||||
private final Queue<ClientPlayPacket> packets = Queues.newConcurrentLinkedQueue();
|
||||
private final Queue<ClientPlayPacket> packets = new ConcurrentLinkedQueue<>();
|
||||
private final boolean levelFlat;
|
||||
private final PlayerSettings settings;
|
||||
private float exp;
|
||||
@ -1379,9 +1379,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
* @param entity the entity to spectate
|
||||
*/
|
||||
public void spectate(@NotNull Entity entity) {
|
||||
CameraPacket cameraPacket = new CameraPacket();
|
||||
cameraPacket.cameraId = entity.getEntityId();
|
||||
playerConnection.sendPacket(cameraPacket);
|
||||
playerConnection.sendPacket(new CameraPacket(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ public class DoNothingGoal extends GoalSelector {
|
||||
public DoNothingGoal(EntityCreature entityCreature, long time, float chance) {
|
||||
super(entityCreature);
|
||||
this.time = time;
|
||||
this.chance = MathUtils.clampFloat(chance, 0, 1);
|
||||
this.chance = MathUtils.clamp(chance, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -8,8 +8,11 @@ import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.LivingEntity;
|
||||
import net.minestom.server.entity.Player;
|
||||
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.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
/**
|
||||
* 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}
|
||||
* 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 GRAVITY = new DamageType("attack.fall");
|
||||
@ -30,6 +33,8 @@ public class DamageType implements DataContainer {
|
||||
}
|
||||
};
|
||||
private final String identifier;
|
||||
private final Object nbtLock = new Object();
|
||||
private final NBTCompound nbt = new NBTCompound();
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
@ -159,4 +164,18 @@ public class DamageType implements DataContainer {
|
||||
public void setData(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.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class ExtensionManager {
|
||||
@ -379,8 +380,14 @@ public class ExtensionManager {
|
||||
*/
|
||||
@Nullable
|
||||
private DiscoveredExtension discoverFromJar(@NotNull File file) {
|
||||
try (ZipFile f = new ZipFile(file);
|
||||
InputStreamReader reader = new InputStreamReader(f.getInputStream(f.getEntry("extension.json")))) {
|
||||
try (ZipFile f = new ZipFile(file);) {
|
||||
|
||||
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.
|
||||
DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class);
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.minestom.server.extras.velocity;
|
||||
|
||||
import com.google.common.net.InetAddresses;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.PlayerSkin;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@ -73,7 +74,12 @@ public final class VelocityProxy {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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.UpdateLightPacket;
|
||||
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.Position;
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.*;
|
||||
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 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 BiomeManager BIOME_MANAGER = MinecraftServer.getBiomeManager();
|
||||
@ -75,6 +78,7 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
|
||||
protected PFColumnarSpace columnarSpace;
|
||||
|
||||
// Data
|
||||
private final NBTCompound nbt = new NBTCompound();
|
||||
protected Data data;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@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
|
||||
@Override
|
||||
public Data getData() {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import com.google.common.collect.Queues;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.pointer.Pointers;
|
||||
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.TimeUpdatePacket;
|
||||
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.utils.BlockPosition;
|
||||
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.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
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
|
||||
* {@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 UpdateManager UPDATE_MANAGER = MinecraftServer.getUpdateManager();
|
||||
@ -98,9 +101,11 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler<
|
||||
protected UUID uniqueId;
|
||||
|
||||
// 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
|
||||
private final Object nbtLock = new Object();
|
||||
private final NBTCompound nbt = new NBTCompound();
|
||||
private Data data;
|
||||
|
||||
// the explosion supplier
|
||||
@ -1061,6 +1066,20 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler<
|
||||
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.
|
||||
* 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
|
||||
*/
|
||||
private void sendBlockChange(@NotNull Chunk chunk, @NotNull BlockPosition blockPosition, short blockStateId) {
|
||||
BlockChangePacket blockChangePacket = new BlockChangePacket();
|
||||
blockChangePacket.blockPosition = blockPosition;
|
||||
blockChangePacket.blockStateId = blockStateId;
|
||||
chunk.sendPacketToViewers(blockChangePacket);
|
||||
chunk.sendPacketToViewers(new BlockChangePacket(blockPosition, blockStateId));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,10 +5,13 @@ import net.minestom.server.data.DataContainer;
|
||||
import net.minestom.server.inventory.click.InventoryClickProcessor;
|
||||
import net.minestom.server.inventory.condition.InventoryCondition;
|
||||
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.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -19,7 +22,7 @@ import java.util.function.UnaryOperator;
|
||||
/**
|
||||
* 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;
|
||||
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
|
||||
protected final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
|
||||
|
||||
private final Object nbtLock = new Object();
|
||||
private final NBTCompound nbt = new NBTCompound();
|
||||
private Data data;
|
||||
|
||||
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
|
||||
public @Nullable Data getData() {
|
||||
return data;
|
||||
|
@ -403,16 +403,11 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl
|
||||
public boolean doubleClick(@NotNull Player player, int slot) {
|
||||
final ItemStack cursor = getCursorItem();
|
||||
final InventoryClickResult clickResult = clickProcessor.doubleClick(this, null, player, slot, cursor);
|
||||
|
||||
if (clickResult == null)
|
||||
return false;
|
||||
|
||||
if (clickResult.doRefresh())
|
||||
update();
|
||||
|
||||
setItemStack(slot, OFFSET, clickResult.getClicked());
|
||||
setCursorItem(clickResult.getCursor());
|
||||
|
||||
return !clickResult.isCancel();
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class ItemMeta implements TagReadable, Writeable {
|
||||
this.canDestroy = new HashSet<>(metaBuilder.canDestroy);
|
||||
this.canPlaceOn = new HashSet<>(metaBuilder.canPlaceOn);
|
||||
|
||||
this.nbt = metaBuilder.nbt;
|
||||
this.nbt = metaBuilder.nbt();
|
||||
this.emptyBuilder = metaBuilder.getSupplier().get();
|
||||
}
|
||||
|
||||
@ -117,11 +117,6 @@ public class ItemMeta implements TagReadable, Writeable {
|
||||
return tag.read(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTag(@NotNull Tag<?> tag) {
|
||||
return nbt.containsKey(tag.getKey());
|
||||
}
|
||||
|
||||
public @NotNull NBTCompound toNBT() {
|
||||
return nbt.deepClone();
|
||||
}
|
||||
@ -169,12 +164,7 @@ public class ItemMeta implements TagReadable, Writeable {
|
||||
@Deprecated
|
||||
@Contract(pure = true)
|
||||
public <T> T getOrDefault(@NotNull Tag<T> tag, @Nullable T defaultValue) {
|
||||
var key = tag.getKey();
|
||||
if (nbt.containsKey(key)) {
|
||||
return tag.read(toNBT());
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
return tag.defaultValue(defaultValue).read(toNBT());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,7 +2,6 @@ package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
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.item.attribute.ItemAttribute;
|
||||
import net.minestom.server.tag.Tag;
|
||||
@ -15,12 +14,17 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
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 boolean unbreakable;
|
||||
@ -36,21 +40,21 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
@Contract("_ -> this")
|
||||
public @NotNull ItemMetaBuilder damage(int damage) {
|
||||
this.damage = damage;
|
||||
this.nbt.setInt("Damage", damage);
|
||||
mutateNbt(compound -> compound.setInt("Damage", damage));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("_ -> this")
|
||||
public @NotNull ItemMetaBuilder unbreakable(boolean unbreakable) {
|
||||
this.unbreakable = unbreakable;
|
||||
this.nbt.setByte("Unbreakable", (byte) (unbreakable ? 1 : 0));
|
||||
mutateNbt(compound -> compound.setByte("Unbreakable", (byte) (unbreakable ? 1 : 0)));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("_ -> this")
|
||||
public @NotNull ItemMetaBuilder hideFlag(int hideFlag) {
|
||||
this.hideFlag = hideFlag;
|
||||
this.nbt.setInt("HideFlags", hideFlag);
|
||||
mutateNbt(compound -> compound.setInt("HideFlags", hideFlag));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -79,7 +83,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
|
||||
@Contract("_ -> this")
|
||||
public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) {
|
||||
this.lore = lore;
|
||||
this.lore = new ArrayList<>(lore);
|
||||
handleCompound("display", nbtCompound -> {
|
||||
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
|
||||
for (Component line : lore) {
|
||||
@ -98,8 +102,8 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
|
||||
@Contract("_ -> this")
|
||||
public @NotNull ItemMetaBuilder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
|
||||
this.enchantmentMap = enchantments;
|
||||
handleMap(enchantmentMap, "Enchantments", nbt, () -> {
|
||||
this.enchantmentMap = new HashMap<>(enchantments);
|
||||
handleMap(enchantmentMap, "Enchantments", () -> {
|
||||
NBTUtils.writeEnchant(nbt, "Enchantments", enchantmentMap);
|
||||
return nbt.get("Enchantments");
|
||||
});
|
||||
@ -115,16 +119,16 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
|
||||
@Contract("-> this")
|
||||
public @NotNull ItemMetaBuilder clearEnchantment() {
|
||||
this.enchantmentMap.clear();
|
||||
this.enchantmentMap = Collections.emptyMap();
|
||||
enchantments(enchantmentMap);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("_ -> this")
|
||||
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);
|
||||
for (ItemAttribute itemAttribute : attributes) {
|
||||
final UUID uuid = itemAttribute.getUuid();
|
||||
@ -147,17 +151,16 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
@Contract("_ -> this")
|
||||
public @NotNull ItemMetaBuilder customModelData(int customModelData) {
|
||||
this.customModelData = customModelData;
|
||||
this.nbt.setInt("CustomModelData", customModelData);
|
||||
mutateNbt(compound -> compound.setInt("CustomModelData", customModelData));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("_ -> this")
|
||||
public @NotNull ItemMetaBuilder canPlaceOn(@NotNull Set<@NotNull Block> blocks) {
|
||||
this.canPlaceOn = blocks;
|
||||
handleCollection(canPlaceOn, "CanPlaceOn", nbt, () -> {
|
||||
this.canPlaceOn = new HashSet<>(blocks);
|
||||
handleCollection(canPlaceOn, "CanPlaceOn", () -> {
|
||||
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
||||
canPlaceOn.forEach(block -> list.add(new NBTString(block.getName())));
|
||||
nbt.set("CanPlaceOn", list);
|
||||
return list;
|
||||
});
|
||||
return this;
|
||||
@ -170,11 +173,10 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
|
||||
@Contract("_ -> this")
|
||||
public @NotNull ItemMetaBuilder canDestroy(@NotNull Set<@NotNull Block> blocks) {
|
||||
this.canDestroy = blocks;
|
||||
handleCollection(canDestroy, "CanDestroy", nbt, () -> {
|
||||
this.canDestroy = new HashSet<>(blocks);
|
||||
handleCollection(canDestroy, "CanDestroy", () -> {
|
||||
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
||||
canDestroy.forEach(block -> list.add(new NBTString(block.getName())));
|
||||
nbt.set("CanDestroy", list);
|
||||
return list;
|
||||
});
|
||||
return this;
|
||||
@ -187,7 +189,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
|
||||
@Override
|
||||
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) {
|
||||
@ -202,63 +204,85 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
|
||||
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,
|
||||
@NotNull Consumer<@NotNull NBTCompound> consumer) {
|
||||
NBTCompound compound = null;
|
||||
boolean newNbt = false;
|
||||
if (nbt.containsKey(key)) {
|
||||
NBT dNbt = nbt.get(key);
|
||||
if (dNbt instanceof NBTCompound) {
|
||||
compound = (NBTCompound) dNbt;
|
||||
}
|
||||
} else {
|
||||
compound = new NBTCompound();
|
||||
newNbt = true;
|
||||
}
|
||||
|
||||
if (compound != null) {
|
||||
consumer.accept(compound);
|
||||
|
||||
if (newNbt && compound.getSize() > 0) {
|
||||
this.nbt.set(key, compound);
|
||||
} else if (!newNbt && compound.getSize() == 0) {
|
||||
this.nbt.removeTag(key);
|
||||
mutateNbt(nbt -> {
|
||||
NBTCompound compound = null;
|
||||
boolean newNbt = false;
|
||||
if (nbt.containsKey(key)) {
|
||||
NBT dNbt = nbt.get(key);
|
||||
if (dNbt instanceof NBTCompound) {
|
||||
compound = (NBTCompound) dNbt;
|
||||
}
|
||||
} else {
|
||||
compound = new NBTCompound();
|
||||
newNbt = true;
|
||||
}
|
||||
|
||||
}
|
||||
if (compound != null) {
|
||||
consumer.accept(compound);
|
||||
|
||||
if (newNbt && compound.getSize() > 0) {
|
||||
this.nbt.set(key, compound);
|
||||
} else if (!newNbt && compound.getSize() == 0) {
|
||||
this.nbt.removeTag(key);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void handleNullable(@Nullable Object value,
|
||||
@NotNull String key,
|
||||
@NotNull NBTCompound nbtCompound,
|
||||
@NotNull Supplier<@NotNull NBT> supplier) {
|
||||
if (value != null) {
|
||||
nbtCompound.set(key, supplier.get());
|
||||
} else {
|
||||
nbtCompound.removeTag(key);
|
||||
}
|
||||
mutateNbt(compound -> {
|
||||
if (value != null) {
|
||||
compound.set(key, supplier.get());
|
||||
} else {
|
||||
compound.removeTag(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void handleCollection(@NotNull Collection<?> objects,
|
||||
@NotNull String key,
|
||||
@NotNull NBTCompound nbtCompound,
|
||||
@NotNull Supplier<@NotNull NBT> supplier) {
|
||||
if (!objects.isEmpty()) {
|
||||
nbtCompound.set(key, supplier.get());
|
||||
} else {
|
||||
nbtCompound.removeTag(key);
|
||||
}
|
||||
mutateNbt(compound -> {
|
||||
if (!objects.isEmpty()) {
|
||||
compound.set(key, supplier.get());
|
||||
} else {
|
||||
compound.removeTag(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void handleMap(@NotNull Map<?, ?> objects,
|
||||
@NotNull String key,
|
||||
@NotNull NBTCompound nbtCompound,
|
||||
@NotNull Supplier<@NotNull NBT> supplier) {
|
||||
if (!objects.isEmpty()) {
|
||||
nbtCompound.set(key, supplier.get());
|
||||
} else {
|
||||
nbtCompound.removeTag(key);
|
||||
}
|
||||
mutateNbt(compound -> {
|
||||
if (!objects.isEmpty()) {
|
||||
compound.set(key, supplier.get());
|
||||
} else {
|
||||
compound.removeTag(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
@ -271,5 +295,4 @@ public abstract class ItemMetaBuilder implements TagWritable {
|
||||
|
||||
public interface Provider<T extends ItemMetaBuilder> {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -203,11 +203,6 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
|
||||
return meta.getTag(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTag(@NotNull Tag<?> tag) {
|
||||
return meta.hasTag(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HoverEvent<HoverEvent.ShowItem> asHoverEvent(@NotNull UnaryOperator<HoverEvent.ShowItem> op) {
|
||||
return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.of(this.material,
|
||||
|
@ -1,8 +1,8 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.metadata.*;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -100,7 +100,7 @@ public class ItemStackBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
@Contract(value = "_ -> this")
|
||||
public @NotNull ItemStackBuilder stackingRule(@Nullable StackingRule stackingRule) {
|
||||
this.stackingRule = stackingRule;
|
||||
@ -109,9 +109,9 @@ public class ItemStackBuilder {
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
public @NotNull ItemStack build() {
|
||||
if (amount > 0)
|
||||
return new ItemStack(material, amount, metaBuilder.build(), stackingRule);
|
||||
return ItemStack.AIR;
|
||||
if (amount < 1)
|
||||
return ItemStack.AIR;
|
||||
return new ItemStack(material, amount, metaBuilder.generate(), stackingRule);
|
||||
}
|
||||
|
||||
private static final class DefaultMeta extends ItemMetaBuilder {
|
||||
@ -130,5 +130,4 @@ public class ItemStackBuilder {
|
||||
return DefaultMeta::new;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,18 +45,20 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
|
||||
|
||||
public Builder lodestoneTracked(boolean lodestoneTracked) {
|
||||
this.lodestoneTracked = lodestoneTracked;
|
||||
this.nbt.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0));
|
||||
mutateNbt(compound -> compound.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder lodestoneDimension(@Nullable String lodestoneDimension) {
|
||||
this.lodestoneDimension = lodestoneDimension;
|
||||
|
||||
if (lodestoneDimension != null) {
|
||||
this.nbt.setString("LodestoneDimension", lodestoneDimension);
|
||||
} else {
|
||||
this.nbt.removeTag("LodestoneDimension");
|
||||
}
|
||||
mutateNbt(compound -> {
|
||||
if (lodestoneDimension != null) {
|
||||
compound.setString("LodestoneDimension", lodestoneDimension);
|
||||
} else {
|
||||
compound.removeTag("LodestoneDimension");
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -64,15 +66,17 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
|
||||
public Builder lodestonePosition(@Nullable Position lodestonePosition) {
|
||||
this.lodestonePosition = lodestonePosition;
|
||||
|
||||
if (lodestonePosition != null) {
|
||||
NBTCompound posCompound = new NBTCompound();
|
||||
posCompound.setInt("X", (int) lodestonePosition.getX());
|
||||
posCompound.setInt("Y", (int) lodestonePosition.getY());
|
||||
posCompound.setInt("Z", (int) lodestonePosition.getZ());
|
||||
this.nbt.set("LodestonePos", posCompound);
|
||||
} else {
|
||||
this.nbt.removeTag("LodestonePos");
|
||||
}
|
||||
mutateNbt(compound -> {
|
||||
if (lodestonePosition != null) {
|
||||
NBTCompound posCompound = new NBTCompound();
|
||||
posCompound.setInt("X", (int) lodestonePosition.getX());
|
||||
posCompound.setInt("Y", (int) lodestonePosition.getY());
|
||||
posCompound.setInt("Z", (int) lodestonePosition.getZ());
|
||||
compound.set("LodestonePos", posCompound);
|
||||
} else {
|
||||
compound.removeTag("LodestonePos");
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
|
||||
if (!projectile.isAir()) {
|
||||
chargedProjectiles.add(getItemCompound(projectile));
|
||||
}
|
||||
this.nbt.set("ChargedProjectiles", chargedProjectiles);
|
||||
mutateNbt(compound -> compound.set("ChargedProjectiles", chargedProjectiles));
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -123,7 +123,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
|
||||
chargedProjectiles.add(getItemCompound(projectile1));
|
||||
chargedProjectiles.add(getItemCompound(projectile2));
|
||||
chargedProjectiles.add(getItemCompound(projectile3));
|
||||
this.nbt.set("ChargedProjectiles", chargedProjectiles);
|
||||
mutateNbt(compound -> compound.set("ChargedProjectiles", chargedProjectiles));
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -135,7 +135,7 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
|
||||
*/
|
||||
public Builder charged(boolean charged) {
|
||||
this.charged = charged;
|
||||
this.nbt.setByte("Charged", (byte) (charged ? 1 : 0));
|
||||
mutateNbt(compound -> compound.setByte("Charged", (byte) (charged ? 1 : 0)));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -35,13 +35,13 @@ public class EnchantedBookMeta extends ItemMeta implements ItemMetaBuilder.Provi
|
||||
|
||||
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;
|
||||
NBTUtils.writeEnchant(nbt, "StoredEnchantments", enchantments);
|
||||
mutateNbt(compound -> NBTUtils.writeEnchant(compound, "StoredEnchantments", enchantments));
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder enchantment(Enchantment enchantment, short level) {
|
||||
public @NotNull Builder enchantment(@NotNull Enchantment enchantment, short level) {
|
||||
this.enchantments.put(enchantment, level);
|
||||
enchantments(enchantments);
|
||||
return this;
|
||||
|
@ -28,7 +28,7 @@ public class FireworkEffectMeta extends ItemMeta implements ItemMetaBuilder.Prov
|
||||
|
||||
public Builder effect(@Nullable FireworkEffect fireworkEffect) {
|
||||
this.fireworkEffect = fireworkEffect;
|
||||
this.nbt.set("Explosion", this.fireworkEffect.asCompound());
|
||||
mutateNbt(compound -> compound.set("Explosion", this.fireworkEffect.asCompound()));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -91,18 +91,18 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
|
||||
|
||||
public Builder mapId(int value) {
|
||||
this.mapId = value;
|
||||
this.nbt.setInt("map", mapId);
|
||||
mutateNbt(compound -> compound.setInt("map", mapId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder mapScaleDirection(int value) {
|
||||
this.mapScaleDirection = value;
|
||||
this.nbt.setInt("map_scale_direction", value);
|
||||
mutateNbt(compound -> compound.setInt("map_scale_direction", value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder decorations(List<MapDecoration> value) {
|
||||
this.decorations = value;
|
||||
this.decorations = new ArrayList<>(value);
|
||||
|
||||
NBTList<NBTCompound> decorationsList = new NBTList<>(NBTTypes.TAG_Compound);
|
||||
for (MapDecoration decoration : decorations) {
|
||||
@ -115,7 +115,7 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
|
||||
|
||||
decorationsList.add(decorationCompound);
|
||||
}
|
||||
this.nbt.set("Decorations", decorationsList);
|
||||
mutateNbt(compound -> compound.set("Decorations", decorationsList));
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -123,14 +123,16 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
|
||||
public Builder mapColor(Color value) {
|
||||
this.mapColor = value;
|
||||
|
||||
NBTCompound displayCompound;
|
||||
if (nbt.containsKey("display")) {
|
||||
displayCompound = nbt.getCompound("display");
|
||||
} else {
|
||||
displayCompound = new NBTCompound();
|
||||
this.nbt.set("display", displayCompound);
|
||||
}
|
||||
displayCompound.setInt("MapColor", mapColor.asRGB());
|
||||
mutateNbt(nbt -> {
|
||||
NBTCompound displayCompound;
|
||||
if (nbt.containsKey("display")) {
|
||||
displayCompound = nbt.getCompound("display");
|
||||
} else {
|
||||
displayCompound = new NBTCompound();
|
||||
nbt.set("display", displayCompound);
|
||||
}
|
||||
displayCompound.setInt("MapColor", mapColor.asRGB());
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider<Pot
|
||||
|
||||
public Builder potionType(@NotNull PotionType potionType) {
|
||||
this.potionType = potionType;
|
||||
this.nbt.setString("Potion", potionType.getNamespaceID().asString());
|
||||
mutateNbt(compound -> compound.setString("Potion", potionType.getNamespaceID().asString()));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -71,14 +71,14 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider<Pot
|
||||
|
||||
potionList.add(potionCompound);
|
||||
}
|
||||
this.nbt.set("CustomPotionEffects", potionList);
|
||||
mutateNbt(compound -> compound.set("CustomPotionEffects", potionList));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder color(@NotNull Color color) {
|
||||
this.color = color;
|
||||
this.nbt.setInt("CustomPotionColor", color.asRGB());
|
||||
mutateNbt(compound -> compound.setInt("CustomPotionColor", color.asRGB()));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package net.minestom.server.item.metadata;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
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.ItemMetaBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -53,22 +52,22 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid
|
||||
|
||||
public Builder author(@Nullable String author) {
|
||||
this.author = author;
|
||||
handleNullable(author, "author", nbt,
|
||||
handleNullable(author, "author",
|
||||
() -> new NBTString(Objects.requireNonNull(author)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder title(@Nullable String title) {
|
||||
this.title = title;
|
||||
handleNullable(title, "title", nbt,
|
||||
handleNullable(title, "title",
|
||||
() -> new NBTString(Objects.requireNonNull(title)));
|
||||
return this;
|
||||
}
|
||||
|
||||
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);
|
||||
for (Component page : pages) {
|
||||
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) {
|
||||
this.resolved = resolved;
|
||||
this.nbt.setByte("resolved", (byte) (resolved ? 1 : 0));
|
||||
mutateNbt(compound -> compound.setByte("resolved", (byte) (resolved ? 1 : 0)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder generation(@Nullable WrittenBookGeneration generation) {
|
||||
this.generation = generation;
|
||||
handleNullable(generation, "generation", nbt,
|
||||
handleNullable(generation, "generation",
|
||||
() -> new NBTInt(Objects.requireNonNull(generation).ordinal()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder author(@Nullable String author) {
|
||||
this.author = author;
|
||||
handleNullable(author, "author", nbt,
|
||||
handleNullable(author, "author",
|
||||
() -> new NBTString(Objects.requireNonNull(author)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder title(@Nullable String title) {
|
||||
this.title = title;
|
||||
handleNullable(title, "title", nbt,
|
||||
handleNullable(title, "title",
|
||||
() -> new NBTString(Objects.requireNonNull(title)));
|
||||
return this;
|
||||
}
|
||||
|
||||
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);
|
||||
for (Component page : pages) {
|
||||
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,
|
||||
//using refreshChunk results in the client not being in sync
|
||||
//after rapid invalid block placements
|
||||
BlockChangePacket blockChangePacket = new BlockChangePacket();
|
||||
blockChangePacket.blockPosition = blockPosition;
|
||||
blockChangePacket.blockStateId = Block.AIR.getBlockId();
|
||||
player.getPlayerConnection().sendPacket(blockChangePacket);
|
||||
player.getPlayerConnection().sendPacket(new BlockChangePacket(blockPosition, Block.AIR.getBlockId()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -263,13 +263,6 @@ public class PlayerDiggingListener {
|
||||
*/
|
||||
private static void sendAcknowledgePacket(@NotNull Player player, @NotNull BlockPosition blockPosition, int blockStateId,
|
||||
@NotNull ClientPlayerDiggingPacket.Status status, boolean success) {
|
||||
AcknowledgePlayerDiggingPacket acknowledgePlayerDiggingPacket = new AcknowledgePlayerDiggingPacket();
|
||||
acknowledgePlayerDiggingPacket.blockPosition = blockPosition;
|
||||
acknowledgePlayerDiggingPacket.blockStateId = blockStateId;
|
||||
acknowledgePlayerDiggingPacket.status = status;
|
||||
acknowledgePlayerDiggingPacket.successful = success;
|
||||
|
||||
player.getPlayerConnection().sendPacket(acknowledgePlayerDiggingPacket);
|
||||
player.getPlayerConnection().sendPacket(new AcknowledgePlayerDiggingPacket(blockPosition, blockStateId, status, success));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,9 +13,6 @@ import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.ServerSocketChannel;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
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.network.PacketProcessor;
|
||||
import net.minestom.server.network.netty.channel.ClientChannel;
|
||||
@ -82,14 +79,7 @@ public final class NettyServer {
|
||||
|
||||
// Find boss/worker event group
|
||||
{
|
||||
if (IOUring.isAvailable()) {
|
||||
boss = new IOUringEventLoopGroup(2);
|
||||
worker = new IOUringEventLoopGroup(workerThreadCount);
|
||||
|
||||
channel = IOUringServerSocketChannel.class;
|
||||
|
||||
LOGGER.info("Using io_uring");
|
||||
} else if (Epoll.isAvailable()) {
|
||||
if (Epoll.isAvailable()) {
|
||||
boss = new EpollEventLoopGroup(2);
|
||||
worker = new EpollEventLoopGroup(workerThreadCount);
|
||||
|
||||
|
@ -16,10 +16,8 @@
|
||||
|
||||
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.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
@ -27,6 +25,8 @@ import net.minestom.server.utils.PacketUtils;
|
||||
import net.minestom.server.utils.Utils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
||||
|
||||
@ -34,7 +34,8 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
||||
|
||||
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) {
|
||||
this.threshold = threshold;
|
||||
@ -42,7 +43,7 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
|
||||
PacketUtils.compressBuffer(compressor, from, to);
|
||||
PacketUtils.compressBuffer(deflater, from, to);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
// TODO optimize to do not initialize arrays each time
|
||||
|
||||
ByteBuf compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, in);
|
||||
ByteBuf uncompressed = MoreByteBufUtils.preferredBuffer(ctx.alloc(), compressor, claimedUncompressedSize);
|
||||
try {
|
||||
compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
|
||||
out.add(uncompressed);
|
||||
in.clear();
|
||||
} catch (Exception e) {
|
||||
uncompressed.release();
|
||||
throw e;
|
||||
} finally {
|
||||
compatibleIn.release();
|
||||
}
|
||||
byte[] input = new byte[in.readableBytes()];
|
||||
in.readBytes(input);
|
||||
|
||||
inflater.setInput(input);
|
||||
byte[] output = new byte[claimedUncompressedSize];
|
||||
inflater.inflate(output);
|
||||
inflater.reset();
|
||||
|
||||
out.add(Unpooled.wrappedBuffer(output));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,22 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AcknowledgePlayerDiggingPacket implements ServerPacket {
|
||||
|
||||
public BlockPosition blockPosition = new BlockPosition(0,0,0);
|
||||
public BlockPosition blockPosition;
|
||||
public int blockStateId;
|
||||
public ClientPlayerDiggingPacket.Status status = ClientPlayerDiggingPacket.Status.STARTED_DIGGING;
|
||||
public ClientPlayerDiggingPacket.Status status;
|
||||
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
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
|
@ -9,13 +9,14 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
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) {
|
||||
this.actionBarText = actionBarText;
|
||||
public ActionBarPacket() {
|
||||
this(Component.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,17 +1,30 @@
|
||||
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.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class AttachEntityPacket implements ServerPacket {
|
||||
|
||||
public int attachedEntityId;
|
||||
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
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
|
@ -12,8 +12,13 @@ public class BlockChangePacket implements ServerPacket {
|
||||
public BlockPosition blockPosition;
|
||||
public int blockStateId;
|
||||
|
||||
public BlockChangePacket(BlockPosition blockPosition, int blockStateId) {
|
||||
this.blockPosition = blockPosition;
|
||||
this.blockStateId = blockStateId;
|
||||
}
|
||||
|
||||
public BlockChangePacket() {
|
||||
blockPosition = new BlockPosition(0,0,0);
|
||||
this(new BlockPosition(0, 0, 0), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
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.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
@ -10,7 +11,17 @@ public class CameraPacket implements ServerPacket {
|
||||
|
||||
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
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
|
@ -26,18 +26,16 @@ public class ChatMessagePacket implements ComponentHoldingServerPacket {
|
||||
public ChatPosition position;
|
||||
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) {
|
||||
this.message = message;
|
||||
this.position = position;
|
||||
this.uuid = Objects.requireNonNullElse(uuid, NULL_UUID);
|
||||
}
|
||||
|
||||
public ChatMessagePacket() {
|
||||
this(Component.empty(), ChatPosition.SYSTEM_MESSAGE, NULL_UUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
writer.writeComponent(message);
|
||||
|
@ -13,7 +13,8 @@ public class ExplosionPacket implements ServerPacket {
|
||||
public byte[] records = new byte[0];
|
||||
public float playerMotionX, playerMotionY, playerMotionZ;
|
||||
|
||||
public ExplosionPacket() {}
|
||||
public ExplosionPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
@ -21,7 +22,7 @@ public class ExplosionPacket implements ServerPacket {
|
||||
writer.writeFloat(y);
|
||||
writer.writeFloat(z);
|
||||
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)
|
||||
writer.writeByte(record);
|
||||
writer.writeFloat(playerMotionX);
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server.scoreboard;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.pointer.Pointers;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -22,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
@ -72,7 +72,7 @@ public class Team implements PacketGroupingAudience {
|
||||
*/
|
||||
private Component suffix;
|
||||
|
||||
private final Set<Player> playerMembers = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
|
||||
private final Set<Player> playerMembers = ConcurrentHashMap.newKeySet();
|
||||
private boolean isPlayerMembersUpToDate;
|
||||
|
||||
// Adventure
|
||||
|
@ -6,7 +6,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
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.Function;
|
||||
import java.util.function.Supplier;
|
||||
@ -21,29 +25,68 @@ import java.util.function.Supplier;
|
||||
@ApiStatus.NonExtendable
|
||||
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 Function<NBTCompound, T> readFunction;
|
||||
private final BiConsumer<NBTCompound, T> writeConsumer;
|
||||
|
||||
private final Supplier<T> defaultValue;
|
||||
|
||||
protected Tag(@NotNull String key,
|
||||
protected Tag(@Nullable String key,
|
||||
@NotNull Function<NBTCompound, T> readFunction,
|
||||
@NotNull BiConsumer<NBTCompound, T> writeConsumer,
|
||||
@Nullable BiConsumer<NBTCompound, T> writeConsumer,
|
||||
@Nullable Supplier<T> defaultValue) {
|
||||
this.key = key;
|
||||
this.readFunction = readFunction;
|
||||
this.writeConsumer = writeConsumer;
|
||||
this.writeConsumer = Objects.requireNonNullElse(writeConsumer, (compound, t) -> {
|
||||
});
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
protected Tag(@NotNull String key,
|
||||
protected Tag(@Nullable String key,
|
||||
@NotNull Function<NBTCompound, T> readFunction,
|
||||
@NotNull BiConsumer<NBTCompound, T> writeConsumer) {
|
||||
@Nullable BiConsumer<NBTCompound, T> writeConsumer) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -60,7 +103,7 @@ public class Tag<T> {
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
public <R> Tag<R> map(@NotNull Function<T, R> readMap,
|
||||
@NotNull Function<R, T> writeMap) {
|
||||
return new Tag<R>(key,
|
||||
return new Tag<>(key,
|
||||
// Read
|
||||
nbtCompound -> {
|
||||
final var old = readFunction.apply(nbtCompound);
|
||||
@ -85,22 +128,26 @@ public class Tag<T> {
|
||||
}
|
||||
|
||||
public @Nullable T read(@NotNull NBTCompound nbtCompound) {
|
||||
if (nbtCompound.containsKey(key)) {
|
||||
return readFunction.apply(nbtCompound);
|
||||
} else {
|
||||
T result = readFunction.apply(nbtCompound);
|
||||
if (result == null) {
|
||||
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) {
|
||||
if (value != null) {
|
||||
if (key == null || value != null) {
|
||||
this.writeConsumer.accept(nbtCompound, value);
|
||||
} else {
|
||||
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) {
|
||||
return new Tag<>(key,
|
||||
nbtCompound -> nbtCompound.getByte(key),
|
||||
@ -149,17 +196,15 @@ public class Tag<T> {
|
||||
(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,
|
||||
nbt -> {
|
||||
var currentNBT = nbt.get(key);
|
||||
|
||||
final var currentNBT = nbt.get(key);
|
||||
// Avoid a NPE when cloning a null variable.
|
||||
if (currentNBT == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return currentNBT.deepClone();
|
||||
return (T) currentNBT.deepClone();
|
||||
},
|
||||
((nbt, value) -> nbt.set(key, value.deepClone())));
|
||||
}
|
||||
@ -176,7 +221,15 @@ public class Tag<T> {
|
||||
(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,
|
||||
nbtCompound -> {
|
||||
final var compound = nbtCompound.getCompound(key);
|
||||
@ -194,4 +247,18 @@ public class Tag<T> {
|
||||
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;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Represents an element which can read and write {@link Tag tags}.
|
||||
*/
|
||||
@Beta
|
||||
@ApiStatus.Experimental
|
||||
public interface TagHandler extends TagReadable, TagWritable {
|
||||
}
|
||||
|
@ -24,7 +24,9 @@ public interface TagReadable {
|
||||
* @param tag the tag to check
|
||||
* @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.
|
||||
@ -38,11 +40,6 @@ public interface TagReadable {
|
||||
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -14,7 +14,7 @@ public interface TagSerializer<T> {
|
||||
* Reads the custom tag from a {@link TagReadable}.
|
||||
*
|
||||
* @param reader the reader
|
||||
* @return the deserialized value
|
||||
* @return the deserialized value, null if invalid
|
||||
*/
|
||||
@Nullable T read(@NotNull TagReadable reader);
|
||||
|
||||
@ -22,7 +22,7 @@ public interface TagSerializer<T> {
|
||||
* Writes the custom tag to a {@link TagWritable}.
|
||||
*
|
||||
* @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);
|
||||
|
||||
default void removeTag(@NotNull Tag<?> tag) {
|
||||
setTag(tag, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an nbt compound to a tag writer.
|
||||
*
|
||||
|
@ -47,10 +47,6 @@ public final class MathUtils {
|
||||
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) {
|
||||
return number >= min && number <= max;
|
||||
}
|
||||
@ -84,11 +80,15 @@ public final class MathUtils {
|
||||
}
|
||||
|
||||
public static int clamp(int value, int min, int max) {
|
||||
if (value < min) {
|
||||
return min;
|
||||
} else {
|
||||
return Math.min(value, max);
|
||||
}
|
||||
return Math.min(Math.max(value, min), 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) {
|
||||
|
@ -1,12 +1,9 @@
|
||||
package net.minestom.server.utils;
|
||||
|
||||
import com.velocitypowered.natives.compression.VelocityCompressor;
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.adventure.AdventureSerializer;
|
||||
import net.minestom.server.adventure.MinestomAdventure;
|
||||
import net.minestom.server.adventure.audience.PacketGroupingAudience;
|
||||
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.Nullable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
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}
|
||||
@ -31,7 +29,7 @@ import java.util.zip.DataFormatException;
|
||||
public final class PacketUtils {
|
||||
|
||||
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() {
|
||||
}
|
||||
@ -189,27 +187,35 @@ public final class PacketUtils {
|
||||
* <p>
|
||||
* {@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 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 boolean compression = packetLength > MinecraftServer.getCompressionThreshold();
|
||||
Utils.writeVarInt(compressionTarget, compression ? packetLength : 0);
|
||||
if (compression) {
|
||||
compress(compressor, packetBuffer, compressionTarget);
|
||||
compress(deflater, packetBuffer, compressionTarget);
|
||||
} else {
|
||||
compressionTarget.writeBytes(packetBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void compress(@NotNull VelocityCompressor compressor, @NotNull ByteBuf uncompressed, @NotNull ByteBuf compressed) {
|
||||
try {
|
||||
compressor.deflate(uncompressed, compressed);
|
||||
} catch (DataFormatException e) {
|
||||
e.printStackTrace();
|
||||
private static void compress(@NotNull Deflater deflater, @NotNull ByteBuf uncompressed, @NotNull ByteBuf compressed) {
|
||||
deflater.setInput(uncompressed.nioBuffer());
|
||||
deflater.finish();
|
||||
|
||||
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,
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server.utils;
|
||||
|
||||
import com.google.common.primitives.Doubles;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.utils.clone.PublicCloneable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -167,7 +166,7 @@ public class Vector implements PublicCloneable<Vector> {
|
||||
* @return angle in radians
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package net.minestom.server.utils.cache;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.RemovalListener;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.RemovalListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -24,7 +24,7 @@ public class TemporaryCache<T> {
|
||||
* @param duration the time before considering an object unused
|
||||
*/
|
||||
public TemporaryCache(long duration, TimeUnit timeUnit, RemovalListener<UUID, T> removalListener) {
|
||||
this.cache = CacheBuilder.newBuilder()
|
||||
this.cache = Caffeine.newBuilder()
|
||||
.expireAfterWrite(duration, timeUnit)
|
||||
.removalListener(removalListener)
|
||||
.build();
|
||||
|
@ -6,8 +6,10 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class TemporaryPacketCache extends TemporaryCache<TimedBuffer> {
|
||||
public TemporaryPacketCache(long duration, TimeUnit timeUnit) {
|
||||
super(duration, timeUnit, notification -> {
|
||||
final ByteBuf buffer = notification.getValue().getBuffer();
|
||||
super(duration, timeUnit, (key, value, cause) -> {
|
||||
if (value == null)
|
||||
return;
|
||||
final ByteBuf buffer = value.getBuffer();
|
||||
synchronized (buffer) {
|
||||
buffer.release();
|
||||
}
|
||||
|
@ -28,4 +28,17 @@ public class RelativeBlockPosition extends RelativeLocation<BlockPosition> {
|
||||
|
||||
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.utils.Position;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -22,19 +23,6 @@ public abstract class RelativeLocation<T> {
|
||||
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}.
|
||||
*
|
||||
@ -43,6 +31,26 @@ public abstract class RelativeLocation<T> {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -28,4 +28,17 @@ public class RelativeVec extends RelativeLocation<Vector> {
|
||||
|
||||
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;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
@ -17,12 +17,12 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
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)
|
||||
.softValues()
|
||||
.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)
|
||||
.softValues()
|
||||
.build();
|
||||
|
@ -55,16 +55,12 @@ public class PlayerInit {
|
||||
.addListener(EntityAttackEvent.class, event -> {
|
||||
final Entity source = event.getEntity();
|
||||
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) {
|
||||
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);
|
||||
} else {
|
||||
Vector velocity = source.getPosition().clone().getDirection().multiply(3);
|
||||
velocity.setY(3f);
|
||||
entity.setVelocity(velocity);
|
||||
}
|
||||
|
||||
if (source instanceof Player) {
|
||||
|
Loading…
Reference in New Issue
Block a user