Merge branch 'master' into velocity-changes

This commit is contained in:
Bloepiloepi 2021-08-22 01:56:45 +02:00 committed by GitHub
commit e902591baa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 261 additions and 236 deletions

View File

@ -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'

View File

@ -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

View File

@ -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);

View File

@ -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;
}
} }
} }

View File

@ -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;
}
} }

View File

@ -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)

View File

@ -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();

View File

@ -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);
} }
} }

View File

@ -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) {

View File

@ -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);

View File

@ -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)) {

View File

@ -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;

View File

@ -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);
}
} }
} }
} }

View File

@ -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);

View File

@ -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);

View File

@ -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}.
* *

View File

@ -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;
} }

View File

@ -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) :

View File

@ -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;

View File

@ -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();

View File

@ -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) {

View File

@ -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();

View File

@ -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();

View File

@ -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);
} }
} }

View File

@ -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");

View File

@ -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);

View File

@ -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);
} }