mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-02 14:38:26 +01:00
Merge branch 'master' into velocity-changes
This commit is contained in:
commit
e902591baa
@ -3,7 +3,7 @@ import org.gradle.internal.os.OperatingSystem
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'org.jetbrains.kotlin.jvm' version '1.5.0'
|
id 'org.jetbrains.kotlin.jvm' version '1.5.21'
|
||||||
id 'checkstyle'
|
id 'checkstyle'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ dependencies {
|
|||||||
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.7.2')
|
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.7.2')
|
||||||
|
|
||||||
// Only here to ensure J9 module support for extensions and our classloaders
|
// Only here to ensure J9 module support for extensions and our classloaders
|
||||||
testCompileOnly 'org.mockito:mockito-core:3.11.1'
|
testCompileOnly 'org.mockito:mockito-core:3.11.2'
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
|
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
|
||||||
api 'it.unimi.dsi:fastutil:8.5.4'
|
api 'it.unimi.dsi:fastutil:8.5.4'
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# Update this version with every release. It is purely used for the code generator and data dependency.
|
# Update this version with every release. It is purely used for the code generator and data dependency.
|
||||||
mcVersion = 1.17
|
mcVersion = 1.17
|
||||||
|
|
||||||
asmVersion=9.0
|
asmVersion=9.2
|
||||||
mixinVersion=0.8.1
|
mixinVersion=0.8.3
|
||||||
hephaistosVersion=v1.1.8
|
hephaistosVersion=v1.1.8
|
||||||
kotlinVersion=1.5.0
|
kotlinVersion=1.5.21
|
||||||
adventureVersion=4.8.1
|
adventureVersion=4.8.1
|
@ -99,22 +99,17 @@ public final class CommandManager {
|
|||||||
* @return the execution result
|
* @return the execution result
|
||||||
*/
|
*/
|
||||||
public @NotNull CommandResult execute(@NotNull CommandSender sender, @NotNull String command) {
|
public @NotNull CommandResult execute(@NotNull CommandSender sender, @NotNull String command) {
|
||||||
|
|
||||||
// Command event
|
// Command event
|
||||||
if (sender instanceof Player) {
|
if (sender instanceof Player) {
|
||||||
Player player = (Player) sender;
|
final Player player = (Player) sender;
|
||||||
|
|
||||||
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, command);
|
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, command);
|
||||||
EventDispatcher.call(playerCommandEvent);
|
EventDispatcher.call(playerCommandEvent);
|
||||||
|
|
||||||
if (playerCommandEvent.isCancelled())
|
if (playerCommandEvent.isCancelled())
|
||||||
return CommandResult.of(CommandResult.Type.CANCELLED, command);
|
return CommandResult.of(CommandResult.Type.CANCELLED, command);
|
||||||
|
|
||||||
command = playerCommandEvent.getCommand();
|
command = playerCommandEvent.getCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the command
|
// Process the command
|
||||||
final var result = dispatcher.execute(sender, command);
|
final CommandResult result = dispatcher.execute(sender, command);
|
||||||
if (result.getType() == CommandResult.Type.UNKNOWN) {
|
if (result.getType() == CommandResult.Type.UNKNOWN) {
|
||||||
if (unknownCommandCallback != null) {
|
if (unknownCommandCallback != null) {
|
||||||
this.unknownCommandCallback.apply(sender, command);
|
this.unknownCommandCallback.apply(sender, command);
|
||||||
|
@ -65,8 +65,7 @@ public class CommandDispatcher {
|
|||||||
this.cache.invalidateAll();
|
this.cache.invalidateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
public @NotNull Set<Command> getCommands() {
|
||||||
public Set<Command> getCommands() {
|
|
||||||
return Collections.unmodifiableSet(commands);
|
return Collections.unmodifiableSet(commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,8 +75,7 @@ public class CommandDispatcher {
|
|||||||
* @param commandName the command name
|
* @param commandName the command name
|
||||||
* @return the {@link Command} associated with the name, null if not any
|
* @return the {@link Command} associated with the name, null if not any
|
||||||
*/
|
*/
|
||||||
@Nullable
|
public @Nullable Command findCommand(@NotNull String commandName) {
|
||||||
public Command findCommand(@NotNull String commandName) {
|
|
||||||
commandName = commandName.toLowerCase();
|
commandName = commandName.toLowerCase();
|
||||||
return commandMap.getOrDefault(commandName, null);
|
return commandMap.getOrDefault(commandName, null);
|
||||||
}
|
}
|
||||||
@ -89,8 +87,7 @@ public class CommandDispatcher {
|
|||||||
* @param commandString the command with the argument(s)
|
* @param commandString the command with the argument(s)
|
||||||
* @return the command result
|
* @return the command result
|
||||||
*/
|
*/
|
||||||
@NotNull
|
public @NotNull CommandResult execute(@NotNull CommandSender source, @NotNull String commandString) {
|
||||||
public CommandResult execute(@NotNull CommandSender source, @NotNull String commandString) {
|
|
||||||
CommandResult commandResult = parse(commandString);
|
CommandResult commandResult = parse(commandString);
|
||||||
ParsedCommand parsedCommand = commandResult.parsedCommand;
|
ParsedCommand parsedCommand = commandResult.parsedCommand;
|
||||||
if (parsedCommand != null) {
|
if (parsedCommand != null) {
|
||||||
@ -105,10 +102,8 @@ public class CommandDispatcher {
|
|||||||
* @param commandString the command (containing the command name and the args if any)
|
* @param commandString the command (containing the command name and the args if any)
|
||||||
* @return the parsing result
|
* @return the parsing result
|
||||||
*/
|
*/
|
||||||
@NotNull
|
public @NotNull CommandResult parse(@NotNull String commandString) {
|
||||||
public CommandResult parse(@NotNull String commandString) {
|
|
||||||
commandString = commandString.trim();
|
commandString = commandString.trim();
|
||||||
|
|
||||||
// Verify if the result is cached
|
// Verify if the result is cached
|
||||||
{
|
{
|
||||||
final CommandResult cachedResult = cache.getIfPresent(commandString);
|
final CommandResult cachedResult = cache.getIfPresent(commandString);
|
||||||
@ -134,18 +129,15 @@ public class CommandDispatcher {
|
|||||||
findParsedCommand(command, commandName, commandQueryResult.args, commandString, result);
|
findParsedCommand(command, commandName, commandQueryResult.args, commandString, result);
|
||||||
|
|
||||||
// Cache result
|
// Cache result
|
||||||
{
|
this.cache.put(commandString, result);
|
||||||
this.cache.put(commandString, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private @Nullable ParsedCommand findParsedCommand(@NotNull Command command,
|
||||||
private ParsedCommand findParsedCommand(@NotNull Command command,
|
@NotNull String commandName, @NotNull String[] args,
|
||||||
@NotNull String commandName, @NotNull String[] args,
|
@NotNull String commandString,
|
||||||
@NotNull String commandString,
|
@NotNull CommandResult result) {
|
||||||
@NotNull CommandResult result) {
|
|
||||||
final boolean hasArgument = args.length > 0;
|
final boolean hasArgument = args.length > 0;
|
||||||
|
|
||||||
// Search for subcommand
|
// Search for subcommand
|
||||||
@ -162,41 +154,37 @@ public class CommandDispatcher {
|
|||||||
|
|
||||||
final String input = commandName + StringUtils.SPACE + String.join(StringUtils.SPACE, args);
|
final String input = commandName + StringUtils.SPACE + String.join(StringUtils.SPACE, args);
|
||||||
|
|
||||||
|
|
||||||
ParsedCommand parsedCommand = new ParsedCommand();
|
ParsedCommand parsedCommand = new ParsedCommand();
|
||||||
parsedCommand.command = command;
|
parsedCommand.command = command;
|
||||||
parsedCommand.commandString = commandString;
|
parsedCommand.commandString = commandString;
|
||||||
|
|
||||||
// The default executor should be used if no argument is provided
|
// The default executor should be used if no argument is provided
|
||||||
{
|
if (!hasArgument) {
|
||||||
if (!hasArgument) {
|
Optional<CommandSyntax> optionalSyntax = command.getSyntaxes()
|
||||||
Optional<CommandSyntax> optionalSyntax = command.getSyntaxes()
|
.stream()
|
||||||
.stream()
|
.filter(syntax -> syntax.getArguments().length == 0)
|
||||||
.filter(syntax -> syntax.getArguments().length == 0)
|
.findFirst();
|
||||||
.findFirst();
|
|
||||||
|
|
||||||
if (optionalSyntax.isPresent()) {
|
if (optionalSyntax.isPresent()) {
|
||||||
// Empty syntax found
|
// Empty syntax found
|
||||||
final CommandSyntax syntax = optionalSyntax.get();
|
final CommandSyntax syntax = optionalSyntax.get();
|
||||||
|
parsedCommand.syntax = syntax;
|
||||||
|
parsedCommand.executor = syntax.getExecutor();
|
||||||
|
parsedCommand.context = new CommandContext(input);
|
||||||
|
|
||||||
parsedCommand.syntax = syntax;
|
result.type = CommandResult.Type.SUCCESS;
|
||||||
parsedCommand.executor = syntax.getExecutor();
|
result.parsedCommand = parsedCommand;
|
||||||
|
return parsedCommand;
|
||||||
|
} else {
|
||||||
|
// No empty syntax, use default executor if any
|
||||||
|
final CommandExecutor defaultExecutor = command.getDefaultExecutor();
|
||||||
|
if (defaultExecutor != null) {
|
||||||
|
parsedCommand.executor = defaultExecutor;
|
||||||
parsedCommand.context = new CommandContext(input);
|
parsedCommand.context = new CommandContext(input);
|
||||||
|
|
||||||
result.type = CommandResult.Type.SUCCESS;
|
result.type = CommandResult.Type.SUCCESS;
|
||||||
result.parsedCommand = parsedCommand;
|
result.parsedCommand = parsedCommand;
|
||||||
return parsedCommand;
|
return parsedCommand;
|
||||||
} else {
|
|
||||||
// No empty syntax, use default executor if any
|
|
||||||
final CommandExecutor defaultExecutor = command.getDefaultExecutor();
|
|
||||||
if (defaultExecutor != null) {
|
|
||||||
parsedCommand.executor = defaultExecutor;
|
|
||||||
parsedCommand.context = new CommandContext(input);
|
|
||||||
|
|
||||||
result.type = CommandResult.Type.SUCCESS;
|
|
||||||
result.parsedCommand = parsedCommand;
|
|
||||||
return parsedCommand;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,7 +195,6 @@ public class CommandDispatcher {
|
|||||||
final Collection<CommandSyntax> syntaxes = command.getSyntaxes();
|
final Collection<CommandSyntax> syntaxes = command.getSyntaxes();
|
||||||
// Contains all the fully validated syntaxes (we later find the one with the most amount of arguments)
|
// Contains all the fully validated syntaxes (we later find the one with the most amount of arguments)
|
||||||
List<ValidSyntaxHolder> validSyntaxes = new ArrayList<>(syntaxes.size());
|
List<ValidSyntaxHolder> validSyntaxes = new ArrayList<>(syntaxes.size());
|
||||||
|
|
||||||
// Contains all the syntaxes that are not fully correct, used to later, retrieve the "most correct syntax"
|
// Contains all the syntaxes that are not fully correct, used to later, retrieve the "most correct syntax"
|
||||||
// Number of correct argument - The data about the failing argument
|
// Number of correct argument - The data about the failing argument
|
||||||
Int2ObjectRBTreeMap<CommandSuggestionHolder> syntaxesSuggestions = new Int2ObjectRBTreeMap<>(Collections.reverseOrder());
|
Int2ObjectRBTreeMap<CommandSuggestionHolder> syntaxesSuggestions = new Int2ObjectRBTreeMap<>(Collections.reverseOrder());
|
||||||
@ -233,29 +220,25 @@ public class CommandDispatcher {
|
|||||||
result.parsedCommand = parsedCommand;
|
result.parsedCommand = parsedCommand;
|
||||||
return parsedCommand;
|
return parsedCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No all-correct syntax, find the closest one to use the argument callback
|
// No all-correct syntax, find the closest one to use the argument callback
|
||||||
{
|
if (!syntaxesSuggestions.isEmpty()) {
|
||||||
// Get closest valid syntax
|
final int max = syntaxesSuggestions.firstIntKey(); // number of correct arguments in the most correct syntax
|
||||||
if (!syntaxesSuggestions.isEmpty()) {
|
final CommandSuggestionHolder suggestionHolder = syntaxesSuggestions.get(max);
|
||||||
final int max = syntaxesSuggestions.firstIntKey(); // number of correct arguments in the most correct syntax
|
final CommandSyntax syntax = suggestionHolder.syntax;
|
||||||
final CommandSuggestionHolder suggestionHolder = syntaxesSuggestions.get(max);
|
final ArgumentSyntaxException argumentSyntaxException = suggestionHolder.argumentSyntaxException;
|
||||||
final CommandSyntax syntax = suggestionHolder.syntax;
|
final int argIndex = suggestionHolder.argIndex;
|
||||||
final ArgumentSyntaxException argumentSyntaxException = suggestionHolder.argumentSyntaxException;
|
|
||||||
final int argIndex = suggestionHolder.argIndex;
|
|
||||||
|
|
||||||
// Found the closest syntax with at least 1 correct argument
|
// Found the closest syntax with at least 1 correct argument
|
||||||
final Argument<?> argument = syntax.getArguments()[argIndex];
|
final Argument<?> argument = syntax.getArguments()[argIndex];
|
||||||
if (argument.hasErrorCallback()) {
|
if (argument.hasErrorCallback() && argumentSyntaxException != null) {
|
||||||
parsedCommand.callback = argument.getCallback();
|
parsedCommand.callback = argument.getCallback();
|
||||||
parsedCommand.argumentSyntaxException = argumentSyntaxException;
|
parsedCommand.argumentSyntaxException = argumentSyntaxException;
|
||||||
|
|
||||||
result.type = CommandResult.Type.INVALID_SYNTAX;
|
result.type = CommandResult.Type.INVALID_SYNTAX;
|
||||||
result.parsedCommand = parsedCommand;
|
result.parsedCommand = parsedCommand;
|
||||||
return parsedCommand;
|
return parsedCommand;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ public final class Pos implements Point {
|
|||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
this.yaw = yaw;
|
this.yaw = fixYaw(yaw);
|
||||||
this.pitch = pitch;
|
this.pitch = pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ public final class Pos implements Point {
|
|||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
public @NotNull Pos withYaw(@NotNull DoubleUnaryOperator operator) {
|
public @NotNull Pos withYaw(@NotNull DoubleUnaryOperator operator) {
|
||||||
return new Pos(x, y, z, (float) operator.applyAsDouble(yaw), pitch);
|
return withYaw((float) operator.applyAsDouble(yaw));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
@ -118,7 +118,7 @@ public final class Pos implements Point {
|
|||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
public @NotNull Pos withPitch(@NotNull DoubleUnaryOperator operator) {
|
public @NotNull Pos withPitch(@NotNull DoubleUnaryOperator operator) {
|
||||||
return new Pos(x, y, z, yaw, (float) operator.applyAsDouble(pitch));
|
return withPitch((float) operator.applyAsDouble(pitch));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -325,4 +325,21 @@ public final class Pos implements Point {
|
|||||||
public interface Operator {
|
public interface Operator {
|
||||||
@NotNull Pos apply(double x, double y, double z, float yaw, float pitch);
|
@NotNull Pos apply(double x, double y, double z, float yaw, float pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes a yaw value that is not between -180.0F and 180.0F
|
||||||
|
* So for example -1355.0F becomes 85.0F and 225.0F becomes -135.0F
|
||||||
|
*
|
||||||
|
* @param yaw The possible "wrong" yaw
|
||||||
|
* @return a fixed yaw
|
||||||
|
*/
|
||||||
|
private static float fixYaw(float yaw) {
|
||||||
|
yaw = yaw % 360;
|
||||||
|
if (yaw < -180.0F) {
|
||||||
|
yaw += 360.0F;
|
||||||
|
} else if (yaw > 180.0F) {
|
||||||
|
yaw -= 360.0F;
|
||||||
|
}
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,8 +557,9 @@ public class Entity implements Viewable, Tickable, TagHandler, PermissionHandler
|
|||||||
|
|
||||||
// Update velocity
|
// Update velocity
|
||||||
if (hasVelocity || !newVelocity.isZero()) {
|
if (hasVelocity || !newVelocity.isZero()) {
|
||||||
|
final double airDrag = this instanceof LivingEntity ? 0.91 : 0.98;
|
||||||
final double drag = this.onGround ?
|
final double drag = this.onGround ?
|
||||||
finalChunk.getBlock(position).registry().friction() : 0.91;
|
finalChunk.getBlock(position).registry().friction() : airDrag;
|
||||||
this.velocity = newVelocity
|
this.velocity = newVelocity
|
||||||
// Convert from block/tick to block/sec
|
// Convert from block/tick to block/sec
|
||||||
.mul(tps)
|
.mul(tps)
|
||||||
|
@ -318,7 +318,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
if (expandedBoundingBox.intersect(itemBoundingBox)) {
|
if (expandedBoundingBox.intersect(itemBoundingBox)) {
|
||||||
if (experienceOrb.shouldRemove() || experienceOrb.isRemoveScheduled())
|
if (experienceOrb.shouldRemove() || experienceOrb.isRemoveScheduled())
|
||||||
continue;
|
continue;
|
||||||
PickupExperienceEvent pickupExperienceEvent = new PickupExperienceEvent(experienceOrb);
|
PickupExperienceEvent pickupExperienceEvent = new PickupExperienceEvent(this, experienceOrb);
|
||||||
EventDispatcher.callCancellable(pickupExperienceEvent, () -> {
|
EventDispatcher.callCancellable(pickupExperienceEvent, () -> {
|
||||||
short experienceCount = pickupExperienceEvent.getExperienceCount(); // TODO give to player
|
short experienceCount = pickupExperienceEvent.getExperienceCount(); // TODO give to player
|
||||||
entity.remove();
|
entity.remove();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.minestom.server.entity.ai.goal;
|
package net.minestom.server.entity.ai.goal;
|
||||||
|
|
||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.entity.Entity;
|
import net.minestom.server.entity.Entity;
|
||||||
import net.minestom.server.entity.EntityCreature;
|
import net.minestom.server.entity.EntityCreature;
|
||||||
import net.minestom.server.entity.ai.GoalSelector;
|
import net.minestom.server.entity.ai.GoalSelector;
|
||||||
@ -15,6 +16,8 @@ public class FollowTargetGoal extends GoalSelector {
|
|||||||
private boolean forceEnd = false;
|
private boolean forceEnd = false;
|
||||||
private Point lastTargetPos;
|
private Point lastTargetPos;
|
||||||
|
|
||||||
|
private Entity target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a follow target goal object.
|
* Creates a follow target goal object.
|
||||||
*
|
*
|
||||||
@ -28,8 +31,14 @@ public class FollowTargetGoal extends GoalSelector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldStart() {
|
public boolean shouldStart() {
|
||||||
return entityCreature.getTarget() != null &&
|
Entity target = entityCreature.getTarget();
|
||||||
entityCreature.getTarget().getPosition().distance(entityCreature.getPosition()) >= 2;
|
if (target == null) target = findTarget();
|
||||||
|
if (target == null) return false;
|
||||||
|
final boolean result = target.getPosition().distance(entityCreature.getPosition()) >= 2;
|
||||||
|
if (result) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -37,23 +46,23 @@ public class FollowTargetGoal extends GoalSelector {
|
|||||||
lastUpdateTime = 0;
|
lastUpdateTime = 0;
|
||||||
forceEnd = false;
|
forceEnd = false;
|
||||||
lastTargetPos = null;
|
lastTargetPos = null;
|
||||||
final Entity target = entityCreature.getTarget();
|
if (target == null) {
|
||||||
if (target != null) {
|
// No defined target
|
||||||
Navigator navigator = entityCreature.getNavigator();
|
this.forceEnd = true;
|
||||||
|
return;
|
||||||
lastTargetPos = target.getPosition();
|
}
|
||||||
if (lastTargetPos.distance(entityCreature.getPosition()) < 2) {
|
this.entityCreature.setTarget(target);
|
||||||
forceEnd = true;
|
Navigator navigator = entityCreature.getNavigator();
|
||||||
navigator.setPathTo(null);
|
this.lastTargetPos = target.getPosition();
|
||||||
return;
|
if (lastTargetPos.distance(entityCreature.getPosition()) < 2) {
|
||||||
}
|
// Target is too far
|
||||||
|
this.forceEnd = true;
|
||||||
if (navigator.getPathPosition() == null ||
|
navigator.setPathTo(null);
|
||||||
(!navigator.getPathPosition().samePoint(lastTargetPos))) {
|
return;
|
||||||
navigator.setPathTo(lastTargetPos);
|
}
|
||||||
} else {
|
if (navigator.getPathPosition() == null ||
|
||||||
forceEnd = true;
|
(!navigator.getPathPosition().samePoint(lastTargetPos))) {
|
||||||
}
|
navigator.setPathTo(lastTargetPos);
|
||||||
} else {
|
} else {
|
||||||
forceEnd = true;
|
forceEnd = true;
|
||||||
}
|
}
|
||||||
@ -66,7 +75,7 @@ public class FollowTargetGoal extends GoalSelector {
|
|||||||
pathDuration.toMillis() + lastUpdateTime > time) {
|
pathDuration.toMillis() + lastUpdateTime > time) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final var targetPos = entityCreature.getTarget() != null ? entityCreature.getTarget().getPosition() : null;
|
final Pos targetPos = entityCreature.getTarget() != null ? entityCreature.getTarget().getPosition() : null;
|
||||||
if (targetPos != null && !targetPos.samePoint(lastTargetPos)) {
|
if (targetPos != null && !targetPos.samePoint(lastTargetPos)) {
|
||||||
this.lastUpdateTime = time;
|
this.lastUpdateTime = time;
|
||||||
this.lastTargetPos = targetPos;
|
this.lastTargetPos = targetPos;
|
||||||
@ -79,11 +88,12 @@ public class FollowTargetGoal extends GoalSelector {
|
|||||||
final Entity target = entityCreature.getTarget();
|
final Entity target = entityCreature.getTarget();
|
||||||
return forceEnd ||
|
return forceEnd ||
|
||||||
target == null ||
|
target == null ||
|
||||||
|
target.isRemoved() ||
|
||||||
target.getPosition().distance(entityCreature.getPosition()) < 2;
|
target.getPosition().distance(entityCreature.getPosition()) < 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void end() {
|
public void end() {
|
||||||
entityCreature.getNavigator().setPathTo(null);
|
this.entityCreature.getNavigator().setPathTo(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ import net.minestom.server.entity.ai.GoalSelector;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class RandomStrollGoal extends GoalSelector {
|
public class RandomStrollGoal extends GoalSelector {
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ public class RandomStrollGoal extends GoalSelector {
|
|||||||
|
|
||||||
private final int radius;
|
private final int radius;
|
||||||
private final List<Vec> closePositions;
|
private final List<Vec> closePositions;
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
private long lastStroll;
|
private long lastStroll;
|
||||||
|
|
||||||
@ -31,8 +32,11 @@ public class RandomStrollGoal extends GoalSelector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void start() {
|
||||||
Collections.shuffle(closePositions);
|
int remainingAttempt = closePositions.size();
|
||||||
for (var position : closePositions) {
|
while (remainingAttempt-- > 0) {
|
||||||
|
final int index = random.nextInt(closePositions.size());
|
||||||
|
final Vec position = closePositions.get(index);
|
||||||
|
|
||||||
final var target = entityCreature.getPosition().add(position);
|
final var target = entityCreature.getPosition().add(position);
|
||||||
final boolean result = entityCreature.getNavigator().setPathTo(target);
|
final boolean result = entityCreature.getNavigator().setPathTo(target);
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -21,6 +21,7 @@ public class ClosestEntityTarget extends TargetSelector {
|
|||||||
private final float range;
|
private final float range;
|
||||||
private final Class<? extends LivingEntity>[] entitiesTarget;
|
private final Class<? extends LivingEntity>[] entitiesTarget;
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
public ClosestEntityTarget(@NotNull EntityCreature entityCreature, float range,
|
public ClosestEntityTarget(@NotNull EntityCreature entityCreature, float range,
|
||||||
@NotNull Class<? extends LivingEntity>... entitiesTarget) {
|
@NotNull Class<? extends LivingEntity>... entitiesTarget) {
|
||||||
super(entityCreature);
|
super(entityCreature);
|
||||||
|
@ -68,8 +68,8 @@ class EventNodeImpl<T extends Event> implements EventNode<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <E extends T> @NotNull List<EventNode<E>> findChildren(@NotNull String name, Class<E> eventType) {
|
public <E extends T> @NotNull List<EventNode<E>> findChildren(@NotNull String name, Class<E> eventType) {
|
||||||
if (children.isEmpty()) return Collections.emptyList();
|
|
||||||
synchronized (GLOBAL_CHILD_LOCK) {
|
synchronized (GLOBAL_CHILD_LOCK) {
|
||||||
|
if (children.isEmpty()) return Collections.emptyList();
|
||||||
List<EventNode<E>> result = new ArrayList<>();
|
List<EventNode<E>> result = new ArrayList<>();
|
||||||
for (EventNode<T> child : children) {
|
for (EventNode<T> child : children) {
|
||||||
if (equals(child, name, eventType)) {
|
if (equals(child, name, eventType)) {
|
||||||
|
@ -1,21 +1,30 @@
|
|||||||
package net.minestom.server.event.item;
|
package net.minestom.server.event.item;
|
||||||
|
|
||||||
import net.minestom.server.entity.ExperienceOrb;
|
import net.minestom.server.entity.ExperienceOrb;
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.trait.CancellableEvent;
|
import net.minestom.server.event.trait.CancellableEvent;
|
||||||
|
import net.minestom.server.event.trait.PlayerEvent;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class PickupExperienceEvent implements CancellableEvent {
|
public class PickupExperienceEvent implements CancellableEvent, PlayerEvent {
|
||||||
|
|
||||||
|
private final Player player;
|
||||||
private final ExperienceOrb experienceOrb;
|
private final ExperienceOrb experienceOrb;
|
||||||
private short experienceCount;
|
private short experienceCount;
|
||||||
|
|
||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
|
|
||||||
public PickupExperienceEvent(@NotNull ExperienceOrb experienceOrb) {
|
public PickupExperienceEvent(@NotNull Player player, @NotNull ExperienceOrb experienceOrb) {
|
||||||
|
this.player = player;
|
||||||
this.experienceOrb = experienceOrb;
|
this.experienceOrb = experienceOrb;
|
||||||
this.experienceCount = experienceOrb.getExperienceCount();
|
this.experienceCount = experienceOrb.getExperienceCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ExperienceOrb getExperienceOrb() {
|
public ExperienceOrb getExperienceOrb() {
|
||||||
return experienceOrb;
|
return experienceOrb;
|
||||||
|
@ -59,34 +59,30 @@ public class OpenToLAN {
|
|||||||
*/
|
*/
|
||||||
public static boolean open(@NotNull OpenToLANConfig config) {
|
public static boolean open(@NotNull OpenToLANConfig config) {
|
||||||
Objects.requireNonNull(config, "config");
|
Objects.requireNonNull(config, "config");
|
||||||
|
if (socket != null) return false;
|
||||||
|
|
||||||
if (socket != null) {
|
int port = config.port;
|
||||||
return false;
|
if (port == 0) {
|
||||||
} else {
|
|
||||||
int port = config.port;
|
|
||||||
|
|
||||||
if (port == 0) {
|
|
||||||
try {
|
|
||||||
port = NetworkUtils.getFreePort();
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.warn("Could not find an open port!", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
socket = new DatagramSocket(port);
|
port = NetworkUtils.getFreePort();
|
||||||
} catch (SocketException e) {
|
} catch (IOException e) {
|
||||||
LOGGER.warn("Could not bind to the port!", e);
|
LOGGER.warn("Could not find an open port!", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
eventCooldown = new Cooldown(config.delayBetweenEvent);
|
|
||||||
task = MinecraftServer.getSchedulerManager().buildTask(OpenToLAN::ping)
|
|
||||||
.repeat(config.delayBetweenPings)
|
|
||||||
.schedule();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket = new DatagramSocket(port);
|
||||||
|
} catch (SocketException e) {
|
||||||
|
LOGGER.warn("Could not bind to the port!", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventCooldown = new Cooldown(config.delayBetweenEvent);
|
||||||
|
task = MinecraftServer.getSchedulerManager().buildTask(OpenToLAN::ping)
|
||||||
|
.repeat(config.delayBetweenPings)
|
||||||
|
.schedule();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,17 +91,13 @@ public class OpenToLAN {
|
|||||||
* @return {@code true} if it was closed, {@code false} if it was already closed
|
* @return {@code true} if it was closed, {@code false} if it was already closed
|
||||||
*/
|
*/
|
||||||
public static boolean close() {
|
public static boolean close() {
|
||||||
if (socket == null) {
|
if (socket == null) return false;
|
||||||
return false;
|
task.cancel();
|
||||||
} else {
|
socket.close();
|
||||||
task.cancel();
|
|
||||||
socket.close();
|
|
||||||
|
|
||||||
task = null;
|
task = null;
|
||||||
socket = null;
|
socket = null;
|
||||||
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,23 +113,21 @@ public class OpenToLAN {
|
|||||||
* Performs the ping.
|
* Performs the ping.
|
||||||
*/
|
*/
|
||||||
private static void ping() {
|
private static void ping() {
|
||||||
if (MinecraftServer.getServer().getPort() != 0) {
|
if (!MinecraftServer.getServer().isOpen()) return;
|
||||||
if (packet == null || eventCooldown.isReady(System.currentTimeMillis())) {
|
if (packet == null || eventCooldown.isReady(System.currentTimeMillis())) {
|
||||||
final ServerListPingEvent event = new ServerListPingEvent(OPEN_TO_LAN);
|
final ServerListPingEvent event = new ServerListPingEvent(OPEN_TO_LAN);
|
||||||
EventDispatcher.call(event);
|
EventDispatcher.call(event);
|
||||||
|
|
||||||
final byte[] data = OPEN_TO_LAN.getPingResponse(event.getResponseData()).getBytes(StandardCharsets.UTF_8);
|
final byte[] data = OPEN_TO_LAN.getPingResponse(event.getResponseData()).getBytes(StandardCharsets.UTF_8);
|
||||||
packet = new DatagramPacket(data, data.length, PING_ADDRESS);
|
packet = new DatagramPacket(data, data.length, PING_ADDRESS);
|
||||||
|
|
||||||
eventCooldown.refreshLastUpdate(System.currentTimeMillis());
|
eventCooldown.refreshLastUpdate(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
try {
|
socket.send(packet);
|
||||||
socket.send(packet);
|
} catch (IOException e) {
|
||||||
} catch (IOException e) {
|
LOGGER.warn("Could not send Open to LAN packet!", e);
|
||||||
LOGGER.warn("Could not send Open to LAN packet!", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,11 +164,7 @@ public class AnvilLoader implements IChunkLoader {
|
|||||||
|
|
||||||
final String tileEntityID = te.getString("id");
|
final String tileEntityID = te.getString("id");
|
||||||
if (tileEntityID != null) {
|
if (tileEntityID != null) {
|
||||||
var handler = BLOCK_MANAGER.getHandler(tileEntityID);
|
final BlockHandler handler = BLOCK_MANAGER.getHandlerOrDummy(tileEntityID);
|
||||||
if (handler == null) {
|
|
||||||
LOGGER.warn("Block {} does not have any corresponding handler, default to dummy.", tileEntityID);
|
|
||||||
handler = BlockHandler.Dummy.get(tileEntityID);
|
|
||||||
}
|
|
||||||
block = block.withHandler(handler);
|
block = block.withHandler(handler);
|
||||||
}
|
}
|
||||||
// Remove anvil tags
|
// Remove anvil tags
|
||||||
@ -237,6 +233,7 @@ public class AnvilLoader implements IChunkLoader {
|
|||||||
try {
|
try {
|
||||||
LOGGER.debug("Attempt saving at {} {}", chunk.getChunkX(), chunk.getChunkZ());
|
LOGGER.debug("Attempt saving at {} {}", chunk.getChunkX(), chunk.getChunkZ());
|
||||||
mcaFile.writeColumn(column);
|
mcaFile.writeColumn(column);
|
||||||
|
mcaFile.forget(column);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e);
|
LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e);
|
||||||
EXCEPTION_MANAGER.handleException(e);
|
EXCEPTION_MANAGER.handleException(e);
|
||||||
|
@ -64,7 +64,7 @@ public class DynamicChunk extends Chunk {
|
|||||||
final int index = ChunkUtils.getBlockIndex(x, y, z);
|
final int index = ChunkUtils.getBlockIndex(x, y, z);
|
||||||
// Handler
|
// Handler
|
||||||
final BlockHandler handler = block.handler();
|
final BlockHandler handler = block.handler();
|
||||||
if (handler != null || block.hasNbt()) {
|
if (handler != null || block.hasNbt() || block.registry().isBlockEntity()) {
|
||||||
this.entries.put(index, block);
|
this.entries.put(index, block);
|
||||||
} else {
|
} else {
|
||||||
this.entries.remove(index);
|
this.entries.remove(index);
|
||||||
|
@ -4,14 +4,18 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||||
import net.minestom.server.utils.validate.Check;
|
import net.minestom.server.utils.validate.Check;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class BlockManager {
|
public class BlockManager {
|
||||||
|
private final static Logger LOGGER = LoggerFactory.getLogger(BlockManager.class);
|
||||||
|
|
||||||
// Namespace -> handler supplier
|
// Namespace -> handler supplier
|
||||||
private final Map<String, Supplier<BlockHandler>> blockHandlerMap = new ConcurrentHashMap<>();
|
private final Map<String, Supplier<BlockHandler>> blockHandlerMap = new ConcurrentHashMap<>();
|
||||||
@ -28,6 +32,16 @@ public class BlockManager {
|
|||||||
return handler != null ? handler.get() : null;
|
return handler != null ? handler.get() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public synchronized @Nullable BlockHandler getHandlerOrDummy(@NotNull String namespace) {
|
||||||
|
BlockHandler handler = getHandler(namespace);
|
||||||
|
if (handler == null) {
|
||||||
|
LOGGER.warn("Block {} does not have any corresponding handler, default to dummy.", namespace);
|
||||||
|
handler = BlockHandler.Dummy.get(namespace);
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a {@link BlockPlacementRule}.
|
* Registers a {@link BlockPlacementRule}.
|
||||||
*
|
*
|
||||||
|
@ -192,6 +192,10 @@ public final class Palette implements PublicCloneable<Palette> {
|
|||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBlocks(long[] blocks) {
|
||||||
|
this.blocks = blocks;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the amount of non air blocks in this section.
|
* Get the amount of non air blocks in this section.
|
||||||
*
|
*
|
||||||
@ -201,6 +205,10 @@ public final class Palette implements PublicCloneable<Palette> {
|
|||||||
return blockCount;
|
return blockCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBlockCount(short blockCount) {
|
||||||
|
this.blockCount = blockCount;
|
||||||
|
}
|
||||||
|
|
||||||
public Short2ShortLinkedOpenHashMap getPaletteBlockMap() {
|
public Short2ShortLinkedOpenHashMap getPaletteBlockMap() {
|
||||||
return paletteBlockMap;
|
return paletteBlockMap;
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,8 @@ public class Inventory extends AbstractInventory implements Viewable {
|
|||||||
final boolean isInWindow = isClickInWindow(slot);
|
final boolean isInWindow = isClickInWindow(slot);
|
||||||
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
||||||
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
||||||
final InventoryClickResult clickResult = clickProcessor.leftClick(player, this, slot, clicked, cursor);
|
final InventoryClickResult clickResult = clickProcessor.leftClick(player,
|
||||||
|
isInWindow ? this : playerInventory, clickSlot, clicked, cursor);
|
||||||
if (clickResult.isCancel()) {
|
if (clickResult.isCancel()) {
|
||||||
updateAll(player);
|
updateAll(player);
|
||||||
return false;
|
return false;
|
||||||
@ -289,7 +290,8 @@ public class Inventory extends AbstractInventory implements Viewable {
|
|||||||
final boolean isInWindow = isClickInWindow(slot);
|
final boolean isInWindow = isClickInWindow(slot);
|
||||||
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
||||||
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
||||||
final InventoryClickResult clickResult = clickProcessor.rightClick(player, this, slot, clicked, cursor);
|
final InventoryClickResult clickResult = clickProcessor.rightClick(player,
|
||||||
|
isInWindow ? this : playerInventory, clickSlot, clicked, cursor);
|
||||||
if (clickResult.isCancel()) {
|
if (clickResult.isCancel()) {
|
||||||
updateAll(player);
|
updateAll(player);
|
||||||
return false;
|
return false;
|
||||||
@ -337,7 +339,8 @@ public class Inventory extends AbstractInventory implements Viewable {
|
|||||||
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
||||||
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
||||||
final ItemStack heldItem = playerInventory.getItemStack(key);
|
final ItemStack heldItem = playerInventory.getItemStack(key);
|
||||||
final InventoryClickResult clickResult = clickProcessor.changeHeld(player, this, slot, key, clicked, heldItem);
|
final InventoryClickResult clickResult = clickProcessor.changeHeld(player,
|
||||||
|
isInWindow ? this : playerInventory, clickSlot, key, clicked, heldItem);
|
||||||
if (clickResult.isCancel()) {
|
if (clickResult.isCancel()) {
|
||||||
updateAll(player);
|
updateAll(player);
|
||||||
return false;
|
return false;
|
||||||
@ -368,8 +371,8 @@ public class Inventory extends AbstractInventory implements Viewable {
|
|||||||
final ItemStack clicked = outsideDrop ?
|
final ItemStack clicked = outsideDrop ?
|
||||||
ItemStack.AIR : (isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot));
|
ItemStack.AIR : (isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot));
|
||||||
final ItemStack cursor = getCursorItem(player);
|
final ItemStack cursor = getCursorItem(player);
|
||||||
final InventoryClickResult clickResult = clickProcessor.drop(player, this,
|
final InventoryClickResult clickResult = clickProcessor.drop(player,
|
||||||
all, slot, button, clicked, cursor);
|
isInWindow ? this : playerInventory, all, clickSlot, button, clicked, cursor);
|
||||||
if (clickResult.isCancel()) {
|
if (clickResult.isCancel()) {
|
||||||
updateAll(player);
|
updateAll(player);
|
||||||
return false;
|
return false;
|
||||||
@ -395,8 +398,9 @@ public class Inventory extends AbstractInventory implements Viewable {
|
|||||||
(isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot)) :
|
(isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot)) :
|
||||||
ItemStack.AIR;
|
ItemStack.AIR;
|
||||||
final ItemStack cursor = getCursorItem(player);
|
final ItemStack cursor = getCursorItem(player);
|
||||||
final InventoryClickResult clickResult = clickProcessor.dragging(player, this,
|
final InventoryClickResult clickResult = clickProcessor.dragging(player,
|
||||||
slot, button,
|
isInWindow ? this : playerInventory,
|
||||||
|
clickSlot, button,
|
||||||
clicked, cursor,
|
clicked, cursor,
|
||||||
|
|
||||||
s -> isClickInWindow(s) ? getItemStack(s) :
|
s -> isClickInWindow(s) ? getItemStack(s) :
|
||||||
|
@ -4,18 +4,15 @@ package net.minestom.server.item;
|
|||||||
* Represents a hide flag which can be applied to an {@link ItemStack} using {@link ItemMetaBuilder#hideFlag(int)}.
|
* Represents a hide flag which can be applied to an {@link ItemStack} using {@link ItemMetaBuilder#hideFlag(int)}.
|
||||||
*/
|
*/
|
||||||
public enum ItemHideFlag {
|
public enum ItemHideFlag {
|
||||||
HIDE_ENCHANTS(1),
|
HIDE_ENCHANTS,
|
||||||
HIDE_ATTRIBUTES(2),
|
HIDE_ATTRIBUTES,
|
||||||
HIDE_UNBREAKABLE(4),
|
HIDE_UNBREAKABLE,
|
||||||
HIDE_DESTROYS(8),
|
HIDE_DESTROYS,
|
||||||
HIDE_PLACED_ON(16),
|
HIDE_PLACED_ON,
|
||||||
HIDE_POTION_EFFECTS(32);
|
HIDE_POTION_EFFECTS,
|
||||||
|
HIDE_DYE;
|
||||||
|
|
||||||
private final int bitFieldPart;
|
private final int bitFieldPart = 1 << this.ordinal();
|
||||||
|
|
||||||
ItemHideFlag(int bit) {
|
|
||||||
this.bitFieldPart = bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBitFieldPart() {
|
public int getBitFieldPart() {
|
||||||
return bitFieldPart;
|
return bitFieldPart;
|
||||||
|
@ -122,6 +122,12 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
|
|||||||
return builder().meta(metaOperator).build();
|
return builder().meta(metaOperator).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
@Contract(value = "_ -> new", pure = true)
|
||||||
|
public @NotNull ItemStack withMeta(@NotNull ItemMeta meta) {
|
||||||
|
return builder().meta(meta).build();
|
||||||
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
public @Nullable Component getDisplayName() {
|
public @Nullable Component getDisplayName() {
|
||||||
return meta.getDisplayName();
|
return meta.getDisplayName();
|
||||||
|
@ -51,6 +51,7 @@ public class ItemStackBuilder {
|
|||||||
MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_CHESTPLATE, LeatherArmorMeta.Builder::new);
|
MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_CHESTPLATE, LeatherArmorMeta.Builder::new);
|
||||||
MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_LEGGINGS, LeatherArmorMeta.Builder::new);
|
MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_LEGGINGS, LeatherArmorMeta.Builder::new);
|
||||||
MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_BOOTS, LeatherArmorMeta.Builder::new);
|
MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_BOOTS, LeatherArmorMeta.Builder::new);
|
||||||
|
MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_HORSE_ARMOR, LeatherArmorMeta.Builder::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ItemStackBuilder(@NotNull Material material) {
|
protected ItemStackBuilder(@NotNull Material material) {
|
||||||
|
@ -31,8 +31,7 @@ import static net.minestom.server.MinecraftServer.*;
|
|||||||
* Be aware that this is not the most accurate method, you should use a proper java profiler depending on your needs.
|
* Be aware that this is not the most accurate method, you should use a proper java profiler depending on your needs.
|
||||||
*/
|
*/
|
||||||
public final class BenchmarkManager {
|
public final class BenchmarkManager {
|
||||||
|
private static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean();
|
||||||
public static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean();
|
|
||||||
private static final List<String> THREADS = new ArrayList<>();
|
private static final List<String> THREADS = new ArrayList<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -46,12 +45,10 @@ public final class BenchmarkManager {
|
|||||||
private final Long2LongMap lastUserTimeMap = new Long2LongOpenHashMap();
|
private final Long2LongMap lastUserTimeMap = new Long2LongOpenHashMap();
|
||||||
private final Long2LongMap lastWaitedMap = new Long2LongOpenHashMap();
|
private final Long2LongMap lastWaitedMap = new Long2LongOpenHashMap();
|
||||||
private final Long2LongMap lastBlockedMap = new Long2LongOpenHashMap();
|
private final Long2LongMap lastBlockedMap = new Long2LongOpenHashMap();
|
||||||
|
|
||||||
private final Map<String, ThreadResult> resultMap = new ConcurrentHashMap<>();
|
private final Map<String, ThreadResult> resultMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private boolean enabled = false;
|
private boolean enabled = false;
|
||||||
private volatile boolean stop = false;
|
private volatile boolean stop = false;
|
||||||
|
|
||||||
private long time;
|
private long time;
|
||||||
|
|
||||||
public void enable(@NotNull Duration duration) {
|
public void enable(@NotNull Duration duration) {
|
||||||
@ -96,13 +93,11 @@ public final class BenchmarkManager {
|
|||||||
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
|
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
public @NotNull Map<String, ThreadResult> getResultMap() {
|
||||||
public Map<String, ThreadResult> getResultMap() {
|
|
||||||
return Collections.unmodifiableMap(resultMap);
|
return Collections.unmodifiableMap(resultMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
public @NotNull Component getCpuMonitoringMessage() {
|
||||||
public Component getCpuMonitoringMessage() {
|
|
||||||
Check.stateCondition(!enabled, "CPU monitoring is only possible when the benchmark manager is enabled.");
|
Check.stateCondition(!enabled, "CPU monitoring is only possible when the benchmark manager is enabled.");
|
||||||
TextComponent.Builder benchmarkMessage = Component.text();
|
TextComponent.Builder benchmarkMessage = Component.text();
|
||||||
for (var resultEntry : resultMap.entrySet()) {
|
for (var resultEntry : resultMap.entrySet()) {
|
||||||
@ -121,23 +116,16 @@ public final class BenchmarkManager {
|
|||||||
benchmarkMessage.append(Component.text("% WAITED ", NamedTextColor.GREEN));
|
benchmarkMessage.append(Component.text("% WAITED ", NamedTextColor.GREEN));
|
||||||
benchmarkMessage.append(Component.newline());
|
benchmarkMessage.append(Component.newline());
|
||||||
}
|
}
|
||||||
|
|
||||||
return benchmarkMessage.build();
|
return benchmarkMessage.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshData() {
|
private void refreshData() {
|
||||||
ThreadInfo[] threadInfo = THREAD_MX_BEAN.getThreadInfo(THREAD_MX_BEAN.getAllThreadIds());
|
ThreadInfo[] threadInfo = THREAD_MX_BEAN.getThreadInfo(THREAD_MX_BEAN.getAllThreadIds());
|
||||||
for (ThreadInfo threadInfo2 : threadInfo) {
|
for (ThreadInfo threadInfo2 : threadInfo) {
|
||||||
|
if (threadInfo2 == null) continue; // Can happen if the thread does not exist
|
||||||
final String name = threadInfo2.getThreadName();
|
final String name = threadInfo2.getThreadName();
|
||||||
boolean shouldBenchmark = false;
|
final boolean shouldBenchmark = THREADS.stream().anyMatch(name::startsWith);
|
||||||
for (String thread : THREADS) {
|
if (!shouldBenchmark) continue;
|
||||||
if (name.startsWith(thread)) {
|
|
||||||
shouldBenchmark = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!shouldBenchmark)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
final long id = threadInfo2.getThreadId();
|
final long id = threadInfo2.getThreadId();
|
||||||
|
|
||||||
|
@ -349,11 +349,14 @@ public final class ConnectionManager {
|
|||||||
if (playerConnection instanceof PlayerSocketConnection) {
|
if (playerConnection instanceof PlayerSocketConnection) {
|
||||||
final PlayerSocketConnection socketConnection = (PlayerSocketConnection) playerConnection;
|
final PlayerSocketConnection socketConnection = (PlayerSocketConnection) playerConnection;
|
||||||
socketConnection.writeAndFlush(disconnectPacket);
|
socketConnection.writeAndFlush(disconnectPacket);
|
||||||
|
playerConnection.disconnect();
|
||||||
try {
|
try {
|
||||||
socketConnection.getChannel().close();
|
socketConnection.getChannel().close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
player.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.players.clear();
|
this.players.clear();
|
||||||
|
@ -6,7 +6,6 @@ import net.minestom.server.listener.manager.PacketListenerManager;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public abstract class ClientPlayPacket implements ClientPacket {
|
public abstract class ClientPlayPacket implements ClientPacket {
|
||||||
|
|
||||||
private static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
|
private static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,5 +18,4 @@ public abstract class ClientPlayPacket implements ClientPacket {
|
|||||||
public void process(@NotNull Player player) {
|
public void process(@NotNull Player player) {
|
||||||
PACKET_LISTENER_MANAGER.processClientPacket(this, player);
|
PACKET_LISTENER_MANAGER.processClientPacket(this, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -114,31 +114,29 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
List<NBTCompound> compounds = new ArrayList<>();
|
List<NBTCompound> compounds = new ArrayList<>();
|
||||||
for (var entry : entries.entrySet()) {
|
for (var entry : entries.entrySet()) {
|
||||||
final int index = entry.getKey();
|
final int index = entry.getKey();
|
||||||
final var block = entry.getValue();
|
final Block block = entry.getValue();
|
||||||
|
final String blockEntity = block.registry().blockEntity();
|
||||||
|
if (blockEntity == null) continue; // Only send block entities to client
|
||||||
|
final NBTCompound resultNbt = new NBTCompound();
|
||||||
|
// Append handler tags
|
||||||
final BlockHandler handler = block.handler();
|
final BlockHandler handler = block.handler();
|
||||||
if (handler == null)
|
if (handler != null) {
|
||||||
continue;
|
final NBTCompound blockNbt = Objects.requireNonNullElseGet(block.nbt(), NBTCompound::new);
|
||||||
final var blockEntityTags = handler.getBlockEntityTags();
|
for (Tag<?> tag : handler.getBlockEntityTags()) {
|
||||||
if (blockEntityTags.isEmpty()) // Verify if the block should be sent as block entity to client
|
final var value = tag.read(blockNbt);
|
||||||
continue;
|
if (value != null) {
|
||||||
final var blockNbt = Objects.requireNonNullElseGet(block.nbt(), NBTCompound::new);
|
// Tag is present and valid
|
||||||
final var resultNbt = new NBTCompound();
|
tag.writeUnsafe(resultNbt, value);
|
||||||
for (Tag<?> tag : blockEntityTags) {
|
}
|
||||||
final var value = tag.read(blockNbt);
|
|
||||||
if (value != null) {
|
|
||||||
// Tag is present and valid
|
|
||||||
tag.writeUnsafe(resultNbt, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Add block entity
|
||||||
if (resultNbt.getSize() > 0) {
|
final var blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
|
||||||
final var blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
|
resultNbt.setString("id", blockEntity)
|
||||||
resultNbt.setString("id", handler.getNamespaceId().asString())
|
.setInt("x", blockPosition.blockX())
|
||||||
.setInt("x", blockPosition.blockX())
|
.setInt("y", blockPosition.blockY())
|
||||||
.setInt("y", blockPosition.blockY())
|
.setInt("z", blockPosition.blockZ());
|
||||||
.setInt("z", blockPosition.blockZ());
|
compounds.add(resultNbt);
|
||||||
compounds.add(resultNbt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
writer.writeVarInt(compounds.size());
|
writer.writeVarInt(compounds.size());
|
||||||
compounds.forEach(nbtCompound -> writer.writeNBT("", nbtCompound));
|
compounds.forEach(nbtCompound -> writer.writeNBT("", nbtCompound));
|
||||||
@ -147,8 +145,8 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(@NotNull BinaryReader reader) {
|
public void read(@NotNull BinaryReader reader) {
|
||||||
chunkX = reader.readInt();
|
this.chunkX = reader.readInt();
|
||||||
chunkZ = reader.readInt();
|
this.chunkZ = reader.readInt();
|
||||||
|
|
||||||
int maskCount = reader.readVarInt();
|
int maskCount = reader.readVarInt();
|
||||||
long[] masks = new long[maskCount];
|
long[] masks = new long[maskCount];
|
||||||
@ -158,7 +156,7 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
try {
|
try {
|
||||||
// TODO: Use heightmaps
|
// TODO: Use heightmaps
|
||||||
// unused at the moment
|
// unused at the moment
|
||||||
heightmapsNBT = (NBTCompound) reader.readTag();
|
this.heightmapsNBT = (NBTCompound) reader.readTag();
|
||||||
|
|
||||||
// Biomes
|
// Biomes
|
||||||
int[] biomesIds = reader.readVarIntArray();
|
int[] biomesIds = reader.readVarIntArray();
|
||||||
@ -168,23 +166,22 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
|
this.sections = new HashMap<>();
|
||||||
int blockArrayLength = reader.readVarInt();
|
int blockArrayLength = reader.readVarInt();
|
||||||
if (maskCount > 0) {
|
if (maskCount > 0) {
|
||||||
final long mask = masks[0]; // TODO support for variable size
|
final long mask = masks[0]; // TODO support for variable size
|
||||||
for (int sectionIndex = 0; sectionIndex < CHUNK_SECTION_COUNT; sectionIndex++) {
|
for (int sectionIndex = 0; sectionIndex < CHUNK_SECTION_COUNT; sectionIndex++) {
|
||||||
boolean hasSection = (mask & 1 << sectionIndex) != 0;
|
final boolean hasSection = (mask & 1 << sectionIndex) != 0;
|
||||||
if (!hasSection)
|
if (!hasSection) continue;
|
||||||
continue;
|
|
||||||
final Section section = sections.computeIfAbsent(sectionIndex, i -> new Section());
|
final Section section = sections.computeIfAbsent(sectionIndex, i -> new Section());
|
||||||
final Palette palette = section.getPalette();
|
final Palette palette = section.getPalette();
|
||||||
short blockCount = reader.readShort();
|
final short blockCount = reader.readShort();
|
||||||
byte bitsPerEntry = reader.readByte();
|
palette.setBlockCount(blockCount);
|
||||||
|
final byte bitsPerEntry = reader.readByte();
|
||||||
// Resize palette if necessary
|
// Resize palette if necessary
|
||||||
if (bitsPerEntry > palette.getBitsPerEntry()) {
|
if (bitsPerEntry > palette.getBitsPerEntry()) {
|
||||||
palette.resize(bitsPerEntry);
|
palette.resize(bitsPerEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve palette values
|
// Retrieve palette values
|
||||||
if (bitsPerEntry < 9) {
|
if (bitsPerEntry < 9) {
|
||||||
int paletteSize = reader.readVarInt();
|
int paletteSize = reader.readVarInt();
|
||||||
@ -194,24 +191,18 @@ public class ChunkDataPacket implements ServerPacket {
|
|||||||
palette.getBlockPaletteMap().put((short) paletteValue, (short) i);
|
palette.getBlockPaletteMap().put((short) paletteValue, (short) i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read blocks
|
// Read blocks
|
||||||
int dataLength = reader.readVarInt();
|
palette.setBlocks(reader.readLongArray());
|
||||||
long[] data = palette.getBlocks();
|
|
||||||
for (int i = 0; i < dataLength; i++) {
|
|
||||||
data[i] = reader.readLong();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block entities
|
// Block entities
|
||||||
final int blockEntityCount = reader.readVarInt();
|
final int blockEntityCount = reader.readVarInt();
|
||||||
|
this.entries = new Int2ObjectOpenHashMap<>(blockEntityCount);
|
||||||
entries = new Int2ObjectOpenHashMap<>();
|
|
||||||
for (int i = 0; i < blockEntityCount; i++) {
|
for (int i = 0; i < blockEntityCount; i++) {
|
||||||
NBTCompound tag = (NBTCompound) reader.readTag();
|
NBTCompound tag = (NBTCompound) reader.readTag();
|
||||||
final String id = tag.getString("id");
|
final String id = tag.getString("id");
|
||||||
// TODO retrieve handler by namespace
|
final BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(id);
|
||||||
final int x = tag.getInt("x");
|
final int x = tag.getInt("x");
|
||||||
final int y = tag.getInt("y");
|
final int y = tag.getInt("y");
|
||||||
final int z = tag.getInt("z");
|
final int z = tag.getInt("z");
|
||||||
|
@ -5,6 +5,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.Selector;
|
import java.nio.channels.Selector;
|
||||||
@ -17,7 +18,7 @@ public final class Server {
|
|||||||
public static final Logger LOGGER = LoggerFactory.getLogger(Server.class);
|
public static final Logger LOGGER = LoggerFactory.getLogger(Server.class);
|
||||||
public static final int WORKER_COUNT = Integer.getInteger("minestom.workers",
|
public static final int WORKER_COUNT = Integer.getInteger("minestom.workers",
|
||||||
Runtime.getRuntime().availableProcessors());
|
Runtime.getRuntime().availableProcessors());
|
||||||
public static final int SOCKET_BUFFER_SIZE = Integer.getInteger("minestom.buffer-size", 262_143);
|
public static final int SOCKET_BUFFER_SIZE = Integer.getInteger("minestom.buffer-size", 1_048_575);
|
||||||
public static final int MAX_PACKET_SIZE = 2_097_151; // 3 bytes var-int
|
public static final int MAX_PACKET_SIZE = 2_097_151; // 3 bytes var-int
|
||||||
public static final boolean NO_DELAY = true;
|
public static final boolean NO_DELAY = true;
|
||||||
|
|
||||||
@ -41,6 +42,12 @@ public final class Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void start(SocketAddress address) throws IOException {
|
public void start(SocketAddress address) throws IOException {
|
||||||
|
if (address instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress inetSocketAddress = (InetSocketAddress) address;
|
||||||
|
this.address = inetSocketAddress.getHostString();
|
||||||
|
this.port = inetSocketAddress.getPort();
|
||||||
|
} // TODO unix domain support
|
||||||
|
|
||||||
this.serverSocket = ServerSocketChannel.open();
|
this.serverSocket = ServerSocketChannel.open();
|
||||||
serverSocket.bind(address);
|
serverSocket.bind(address);
|
||||||
serverSocket.configureBlocking(false);
|
serverSocket.configureBlocking(false);
|
||||||
|
@ -235,6 +235,7 @@ public class BinaryWriter extends OutputStream {
|
|||||||
* @param bytes the byte array to write
|
* @param bytes the byte array to write
|
||||||
*/
|
*/
|
||||||
public void writeBytes(byte @NotNull [] bytes) {
|
public void writeBytes(byte @NotNull [] bytes) {
|
||||||
|
if (bytes.length == 0) return;
|
||||||
ensureSize(bytes.length);
|
ensureSize(bytes.length);
|
||||||
buffer.put(bytes);
|
buffer.put(bytes);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user