mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-07 08:58:20 +01:00
Merge branch 'master' into item-api
# Conflicts: # src/test/java/demo/PlayerInit.java
This commit is contained in:
commit
1d5262caf2
@ -2,7 +2,7 @@ package net.minestom.server;
|
||||
|
||||
import net.minestom.server.advancements.AdvancementManager;
|
||||
import net.minestom.server.adventure.bossbar.BossBarManager;
|
||||
import net.minestom.server.benchmark.BenchmarkManager;
|
||||
import net.minestom.server.monitoring.BenchmarkManager;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
import net.minestom.server.data.DataManager;
|
||||
import net.minestom.server.data.DataType;
|
||||
|
@ -4,6 +4,7 @@ import com.google.common.collect.Queues;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.InstanceManager;
|
||||
import net.minestom.server.monitoring.TickMonitor;
|
||||
import net.minestom.server.network.ConnectionManager;
|
||||
import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.thread.PerInstanceThreadProvider;
|
||||
@ -13,10 +14,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.LongConsumer;
|
||||
|
||||
/**
|
||||
@ -36,6 +35,7 @@ public final class UpdateManager {
|
||||
|
||||
private final Queue<LongConsumer> tickStartCallbacks = Queues.newConcurrentLinkedQueue();
|
||||
private final Queue<LongConsumer> tickEndCallbacks = Queues.newConcurrentLinkedQueue();
|
||||
private final List<Consumer<TickMonitor>> tickMonitors = new CopyOnWriteArrayList<>();
|
||||
|
||||
{
|
||||
// DEFAULT THREAD PROVIDER
|
||||
@ -81,7 +81,14 @@ public final class UpdateManager {
|
||||
final long tickTime = System.nanoTime() - currentTime;
|
||||
|
||||
// Tick end callbacks
|
||||
doTickCallback(tickEndCallbacks, tickTime / 1000000L);
|
||||
doTickCallback(tickEndCallbacks, tickTime);
|
||||
|
||||
// Monitoring
|
||||
if (!tickMonitors.isEmpty()) {
|
||||
final double tickTimeMs = tickTime / 1e6D;
|
||||
final TickMonitor tickMonitor = new TickMonitor(tickTimeMs);
|
||||
this.tickMonitors.forEach(consumer -> consumer.accept(tickMonitor));
|
||||
}
|
||||
|
||||
// Flush all waiting packets
|
||||
AsyncUtils.runAsync(() -> connectionManager.getOnlinePlayers().stream()
|
||||
@ -246,6 +253,14 @@ public final class UpdateManager {
|
||||
this.tickEndCallbacks.remove(callback);
|
||||
}
|
||||
|
||||
public void addTickMonitor(@NotNull Consumer<TickMonitor> consumer) {
|
||||
this.tickMonitors.add(consumer);
|
||||
}
|
||||
|
||||
public void removeTickMonitor(@NotNull Consumer<TickMonitor> consumer) {
|
||||
this.tickMonitors.remove(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the server loop.
|
||||
*/
|
||||
|
@ -32,21 +32,22 @@ public class CollisionUtils {
|
||||
@NotNull Vector velocityOut) {
|
||||
// TODO handle collisions with nearby entities (should it be done here?)
|
||||
final Instance instance = entity.getInstance();
|
||||
final Chunk originChunk = entity.getChunk();
|
||||
final Position currentPosition = entity.getPosition();
|
||||
final BoundingBox boundingBox = entity.getBoundingBox();
|
||||
|
||||
Vector intermediaryPosition = new Vector();
|
||||
final boolean yCollision = stepAxis(instance, currentPosition.toVector(), Y_AXIS, deltaPosition.getY(),
|
||||
final boolean yCollision = stepAxis(instance, originChunk, currentPosition.toVector(), Y_AXIS, deltaPosition.getY(),
|
||||
intermediaryPosition,
|
||||
deltaPosition.getY() > 0 ? boundingBox.getTopFace() : boundingBox.getBottomFace()
|
||||
);
|
||||
|
||||
final boolean xCollision = stepAxis(instance, intermediaryPosition, X_AXIS, deltaPosition.getX(),
|
||||
final boolean xCollision = stepAxis(instance, originChunk, intermediaryPosition, X_AXIS, deltaPosition.getX(),
|
||||
intermediaryPosition,
|
||||
deltaPosition.getX() < 0 ? boundingBox.getLeftFace() : boundingBox.getRightFace()
|
||||
);
|
||||
|
||||
final boolean zCollision = stepAxis(instance, intermediaryPosition, Z_AXIS, deltaPosition.getZ(),
|
||||
final boolean zCollision = stepAxis(instance, originChunk, intermediaryPosition, Z_AXIS, deltaPosition.getZ(),
|
||||
intermediaryPosition,
|
||||
deltaPosition.getZ() > 0 ? boundingBox.getBackFace() : boundingBox.getFrontFace()
|
||||
);
|
||||
@ -80,7 +81,11 @@ public class CollisionUtils {
|
||||
* @param corners the corners to check against
|
||||
* @return true if a collision has been found
|
||||
*/
|
||||
private static boolean stepAxis(Instance instance, Vector startPosition, Vector axis, double stepAmount, Vector positionOut, Vector... corners) {
|
||||
private static boolean stepAxis(Instance instance,
|
||||
Chunk originChunk,
|
||||
Vector startPosition, Vector axis,
|
||||
double stepAmount, Vector positionOut,
|
||||
Vector... corners) {
|
||||
positionOut.copy(startPosition);
|
||||
if (corners.length == 0)
|
||||
return false; // avoid degeneracy in following computations
|
||||
@ -99,7 +104,7 @@ public class CollisionUtils {
|
||||
// used to determine if 'remainingLength' should be used
|
||||
boolean collisionFound = false;
|
||||
for (int i = 0; i < Math.abs(blockLength); i++) {
|
||||
if (!stepOnce(instance, axis, sign, cornersCopy, cornerPositions)) {
|
||||
if (!stepOnce(instance, originChunk, axis, sign, cornersCopy, cornerPositions)) {
|
||||
collisionFound = true;
|
||||
}
|
||||
if (collisionFound) {
|
||||
@ -111,7 +116,7 @@ public class CollisionUtils {
|
||||
if (!collisionFound) {
|
||||
Vector direction = new Vector();
|
||||
direction.copy(axis);
|
||||
collisionFound = !stepOnce(instance, direction, remainingLength, cornersCopy, cornerPositions);
|
||||
collisionFound = !stepOnce(instance, originChunk, direction, remainingLength, cornersCopy, cornerPositions);
|
||||
}
|
||||
|
||||
// find the corner which moved the least
|
||||
@ -138,7 +143,9 @@ public class CollisionUtils {
|
||||
* @param cornerPositions the corners, converted to BlockPosition (mutable)
|
||||
* @return false if this method encountered a collision
|
||||
*/
|
||||
private static boolean stepOnce(Instance instance, Vector axis, double amount, Vector[] cornersCopy, BlockPosition[] cornerPositions) {
|
||||
private static boolean stepOnce(Instance instance,
|
||||
Chunk originChunk,
|
||||
Vector axis, double amount, Vector[] cornersCopy, BlockPosition[] cornerPositions) {
|
||||
final double sign = Math.signum(amount);
|
||||
for (int cornerIndex = 0; cornerIndex < cornersCopy.length; cornerIndex++) {
|
||||
Vector corner = cornersCopy[cornerIndex];
|
||||
@ -148,10 +155,13 @@ public class CollisionUtils {
|
||||
blockPos.setY((int) Math.floor(corner.getY()));
|
||||
blockPos.setZ((int) Math.floor(corner.getZ()));
|
||||
|
||||
final Chunk chunk = instance.getChunkAt(blockPos);
|
||||
if (!ChunkUtils.isLoaded(chunk)) {
|
||||
// Collision at chunk border
|
||||
return false;
|
||||
Chunk chunk = originChunk;
|
||||
if (!ChunkUtils.same(originChunk, blockPos.getX(), blockPos.getZ())) {
|
||||
chunk = instance.getChunkAt(blockPos);
|
||||
if (!ChunkUtils.isLoaded(chunk)) {
|
||||
// Collision at chunk border
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final short blockStateId = chunk.getBlockStateId(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||
|
@ -79,10 +79,10 @@ public class ArgumentEntity extends Argument<EntityFinder> {
|
||||
argumentNode.properties = BinaryWriter.makeArray(packetWriter -> {
|
||||
byte mask = 0;
|
||||
if (this.isOnlySingleEntity()) {
|
||||
mask += 1;
|
||||
mask |= 0x01;
|
||||
}
|
||||
if (this.isOnlyPlayers()) {
|
||||
mask += 2;
|
||||
mask |= 0x02;
|
||||
}
|
||||
packetWriter.writeByte(mask);
|
||||
});
|
||||
|
@ -64,6 +64,7 @@ public class Entity implements Viewable, EventHandler, DataContainer, Permission
|
||||
private static final AtomicInteger LAST_ENTITY_ID = new AtomicInteger();
|
||||
|
||||
protected Instance instance;
|
||||
protected Chunk currentChunk;
|
||||
protected final Position position;
|
||||
protected double lastX, lastY, lastZ;
|
||||
protected double cacheX, cacheY, cacheZ; // Used to synchronize with #getPosition
|
||||
@ -462,7 +463,6 @@ public class Entity implements Viewable, EventHandler, DataContainer, Permission
|
||||
}
|
||||
|
||||
// Check if the entity chunk is loaded
|
||||
final Chunk currentChunk = getChunk();
|
||||
if (!ChunkUtils.isLoaded(currentChunk)) {
|
||||
// No update for entities in unloaded chunk
|
||||
return;
|
||||
@ -566,11 +566,14 @@ public class Entity implements Viewable, EventHandler, DataContainer, Permission
|
||||
|
||||
// World border collision
|
||||
final Position finalVelocityPosition = CollisionUtils.applyWorldBorder(instance, position, newPosition);
|
||||
final Chunk finalChunk = instance.getChunkAt(finalVelocityPosition);
|
||||
Chunk finalChunk = currentChunk;
|
||||
if (!ChunkUtils.same(position, finalVelocityPosition)) {
|
||||
finalChunk = instance.getChunkAt(finalVelocityPosition);
|
||||
|
||||
// Entity shouldn't be updated when moving in an unloaded chunk
|
||||
if (!ChunkUtils.isLoaded(finalChunk)) {
|
||||
return;
|
||||
// Entity shouldn't be updated when moving in an unloaded chunk
|
||||
if (!ChunkUtils.isLoaded(finalChunk)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the position if changed
|
||||
@ -637,9 +640,12 @@ public class Entity implements Viewable, EventHandler, DataContainer, Permission
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
final Chunk chunk = instance.getChunkAt(x, z);
|
||||
if (!ChunkUtils.isLoaded(chunk))
|
||||
continue;
|
||||
Chunk chunk = currentChunk;
|
||||
if (!ChunkUtils.same(currentChunk, x, z)) {
|
||||
chunk = instance.getChunkAt(x, z);
|
||||
if (!ChunkUtils.isLoaded(chunk))
|
||||
continue;
|
||||
}
|
||||
|
||||
final CustomBlock customBlock = chunk.getCustomBlock(x, y, z);
|
||||
if (customBlock != null) {
|
||||
@ -816,9 +822,8 @@ public class Entity implements Viewable, EventHandler, DataContainer, Permission
|
||||
*
|
||||
* @return the entity chunk, can be null even if unlikely
|
||||
*/
|
||||
@Nullable
|
||||
public Chunk getChunk() {
|
||||
return instance.getChunkAt(position.getX(), position.getZ());
|
||||
public @Nullable Chunk getChunk() {
|
||||
return currentChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -826,8 +831,7 @@ public class Entity implements Viewable, EventHandler, DataContainer, Permission
|
||||
*
|
||||
* @return the entity instance, can be null if the entity doesn't have an instance yet
|
||||
*/
|
||||
@Nullable
|
||||
public Instance getInstance() {
|
||||
public @Nullable Instance getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@ -855,6 +859,7 @@ public class Entity implements Viewable, EventHandler, DataContainer, Permission
|
||||
|
||||
this.isActive = true;
|
||||
this.instance = instance;
|
||||
this.currentChunk = instance.getChunkAt(position.getX(), position.getZ());
|
||||
instance.UNSAFE_addEntity(this);
|
||||
spawn();
|
||||
EntitySpawnEvent entitySpawnEvent = new EntitySpawnEvent(this, instance);
|
||||
@ -1309,20 +1314,26 @@ public class Entity implements Viewable, EventHandler, DataContainer, Permission
|
||||
|
||||
final Instance instance = getInstance();
|
||||
if (instance != null) {
|
||||
final Chunk lastChunk = instance.getChunkAt(lastX, lastZ);
|
||||
final Chunk newChunk = instance.getChunkAt(x, z);
|
||||
final int lastChunkX = currentChunk.getChunkX();
|
||||
final int lastChunkZ = currentChunk.getChunkZ();
|
||||
|
||||
Check.notNull(lastChunk, "The entity {0} was in an unloaded chunk at {1};{2}", getEntityId(), lastX, lastZ);
|
||||
Check.notNull(newChunk, "The entity {0} tried to move in an unloaded chunk at {1};{2}", getEntityId(), x, z);
|
||||
final int newChunkX = ChunkUtils.getChunkCoordinate(x);
|
||||
final int newChunkZ = ChunkUtils.getChunkCoordinate(z);
|
||||
|
||||
if (lastChunk != newChunk) {
|
||||
instance.UNSAFE_switchEntityChunk(this, lastChunk, newChunk);
|
||||
if (lastChunkX != newChunkX || lastChunkZ != newChunkZ) {
|
||||
// Entity moved in a new chunk
|
||||
final Chunk newChunk = instance.getChunk(newChunkX, newChunkZ);
|
||||
Check.notNull(newChunk, "The entity {0} tried to move in an unloaded chunk at {1};{2}", getEntityId(), x, z);
|
||||
|
||||
instance.UNSAFE_switchEntityChunk(this, currentChunk, newChunk);
|
||||
if (this instanceof Player) {
|
||||
// Refresh player view
|
||||
final Player player = (Player) this;
|
||||
player.refreshVisibleChunks(newChunk);
|
||||
player.refreshVisibleEntities(newChunk);
|
||||
}
|
||||
|
||||
this.currentChunk = newChunk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -664,17 +664,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
// Load all the required chunks
|
||||
final long[] visibleChunks = ChunkUtils.getChunksInRange(spawnPosition, getChunkRange());
|
||||
|
||||
final ChunkCallback eachCallback = chunk -> {
|
||||
if (chunk != null) {
|
||||
final int chunkX = ChunkUtils.getChunkCoordinate(spawnPosition.getX());
|
||||
final int chunkZ = ChunkUtils.getChunkCoordinate(spawnPosition.getZ());
|
||||
if (chunk.getChunkX() == chunkX &&
|
||||
chunk.getChunkZ() == chunkZ) {
|
||||
updateViewPosition(chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final ChunkCallback endCallback = chunk -> {
|
||||
// This is the last chunk to be loaded , spawn player
|
||||
spawnPlayer(instance, spawnPosition, firstSpawn, true, dimensionChange);
|
||||
@ -683,7 +672,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
// Chunk 0;0 always needs to be loaded
|
||||
instance.loadChunk(0, 0, chunk ->
|
||||
// Load all the required chunks
|
||||
ChunkUtils.optionalLoadAll(instance, visibleChunks, eachCallback, endCallback));
|
||||
ChunkUtils.optionalLoadAll(instance, visibleChunks, null, endCallback));
|
||||
|
||||
} else {
|
||||
// The player already has the good version of all the chunks.
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.minestom.server.benchmark;
|
||||
package net.minestom.server.monitoring;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2LongMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
|
@ -1,4 +1,4 @@
|
||||
package net.minestom.server.benchmark;
|
||||
package net.minestom.server.monitoring;
|
||||
|
||||
public class ThreadResult {
|
||||
|
@ -0,0 +1,14 @@
|
||||
package net.minestom.server.monitoring;
|
||||
|
||||
public class TickMonitor {
|
||||
|
||||
private final double tickTime;
|
||||
|
||||
public TickMonitor(double tickTime) {
|
||||
this.tickTime = tickTime;
|
||||
}
|
||||
|
||||
public double getTickTime() {
|
||||
return tickTime;
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler {
|
||||
register(0x27, ClientUpdateCommandBlockMinecartPacket::new);
|
||||
register(0x28, ClientCreativeInventoryActionPacket::new);
|
||||
//Update Jigsaw Block??
|
||||
//Update Structure Block??
|
||||
register(0x2A, ClientUpdateStructureBlockPacket::new);
|
||||
register(0x2B, ClientUpdateSignPacket::new);
|
||||
register(0x2C, ClientAnimationPacket::new);
|
||||
register(0x2D, ClientSpectatePacket::new);
|
||||
|
@ -48,7 +48,7 @@ public class LoginPluginResponsePacket implements ClientPreplayPacket {
|
||||
|
||||
// Velocity
|
||||
if (VelocityProxy.isEnabled() && channel.equals(VelocityProxy.PLAYER_INFO_CHANNEL)) {
|
||||
if (data != null) {
|
||||
if (data != null && data.length > 0) {
|
||||
BinaryReader reader = new BinaryReader(data);
|
||||
success = VelocityProxy.checkIntegrity(reader);
|
||||
if (success) {
|
||||
@ -103,7 +103,7 @@ public class LoginPluginResponsePacket implements ClientPreplayPacket {
|
||||
writer.writeVarInt(messageId);
|
||||
writer.writeBoolean(successful);
|
||||
|
||||
if(successful) {
|
||||
if (successful) {
|
||||
writer.writeBytes(data);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,111 @@
|
||||
package net.minestom.server.network.packet.client.play;
|
||||
|
||||
import net.minestom.server.network.packet.client.ClientPlayPacket;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.Rotation;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ClientUpdateStructureBlockPacket extends ClientPlayPacket {
|
||||
// Flag values
|
||||
public static final byte IGNORE_ENTITIES = 0x1;
|
||||
public static final byte SHOW_AIR = 0x2;
|
||||
/**
|
||||
* Requires the player to be in creative and have a permission level higher than 2.
|
||||
*/
|
||||
public static final byte SHOW_BOUNDING_BOX = 0x4;
|
||||
|
||||
public BlockPosition location = new BlockPosition(0, 0, 0);
|
||||
public Action action = Action.UPDATE_DATA;
|
||||
public Mode mode = Mode.DATA;
|
||||
public String name = "";
|
||||
public BlockPosition offset = new BlockPosition(0, 1, 0);
|
||||
public BlockPosition size = new BlockPosition(1, 1, 1);
|
||||
public Mirror mirror = Mirror.NONE;
|
||||
public Rotation rotation = Rotation.NONE;
|
||||
public String metadata = "";
|
||||
public float integrity = 1.0f;
|
||||
public long seed = 0;
|
||||
public byte flags = 0x0;
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
writer.writeBlockPosition(location);
|
||||
writer.writeVarInt(action.ordinal());
|
||||
writer.writeVarInt(mode.ordinal());
|
||||
writer.writeSizedString(name);
|
||||
writer.writeByte((byte) offset.getX());
|
||||
writer.writeByte((byte) offset.getY());
|
||||
writer.writeByte((byte) offset.getZ());
|
||||
writer.writeByte((byte) size.getX());
|
||||
writer.writeByte((byte) size.getY());
|
||||
writer.writeByte((byte) size.getZ());
|
||||
writer.writeVarInt(mirror.ordinal());
|
||||
writer.writeVarInt(toRestrictedRotation(rotation));
|
||||
writer.writeSizedString(metadata);
|
||||
writer.writeFloat(integrity);
|
||||
writer.writeVarLong(seed);
|
||||
writer.writeByte(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull BinaryReader reader) {
|
||||
location = reader.readBlockPosition();
|
||||
action = Action.values()[reader.readVarInt()];
|
||||
mode = Mode.values()[reader.readVarInt()];
|
||||
name = reader.readSizedString(Short.MAX_VALUE);
|
||||
offset = new BlockPosition(
|
||||
reader.readByte(),
|
||||
reader.readByte(),
|
||||
reader.readByte()
|
||||
);
|
||||
size = new BlockPosition(
|
||||
reader.readByte(),
|
||||
reader.readByte(),
|
||||
reader.readByte()
|
||||
);
|
||||
mirror = Mirror.values()[reader.readVarInt()];
|
||||
rotation = fromRestrictedRotation(reader.readVarInt());
|
||||
metadata = reader.readSizedString(Short.MAX_VALUE);
|
||||
integrity = reader.readFloat();
|
||||
seed = reader.readVarLong();
|
||||
flags = reader.readByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update action, <code>UPDATE_DATA</code> indicates nothing special.
|
||||
*/
|
||||
public enum Action {
|
||||
UPDATE_DATA, SAVE, LOAD, DETECT_SIZE
|
||||
}
|
||||
|
||||
public enum Mode {
|
||||
SAVE, LOAD, CORNER, DATA
|
||||
}
|
||||
|
||||
public enum Mirror {
|
||||
NONE, LEFT_RIGHT, FRONT_BACK
|
||||
}
|
||||
|
||||
private int toRestrictedRotation(Rotation rotation) {
|
||||
switch (rotation) {
|
||||
case NONE: return 0;
|
||||
case CLOCKWISE: return 1;
|
||||
case FLIPPED: return 2;
|
||||
case COUNTER_CLOCKWISE: return 3;
|
||||
default: throw new IllegalArgumentException("ClientUpdateStructurePacket#rotation must be a valid 90-degree rotation.");
|
||||
}
|
||||
}
|
||||
|
||||
private Rotation fromRestrictedRotation(int rotation) {
|
||||
switch (rotation) {
|
||||
case 0: return Rotation.NONE;
|
||||
case 1: return Rotation.CLOCKWISE;
|
||||
case 2: return Rotation.FLIPPED;
|
||||
case 3: return Rotation.COUNTER_CLOCKWISE;
|
||||
default: throw new IllegalArgumentException("ClientUpdateStructurePacket#rotation must be a valid 90-degree rotation.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -22,13 +22,13 @@ public class PlayerAbilitiesPacket implements ServerPacket {
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
byte flags = 0;
|
||||
if (invulnerable)
|
||||
flags += 1;
|
||||
flags |= 0x01;
|
||||
if (flying)
|
||||
flags += 2;
|
||||
flags |= 0x02;
|
||||
if (allowFlying)
|
||||
flags += 4;
|
||||
flags |= 0x04;
|
||||
if (instantBreak)
|
||||
flags += 8;
|
||||
flags |= 0x08;
|
||||
|
||||
writer.writeByte(flags);
|
||||
writer.writeFloat(flyingSpeed);
|
||||
|
@ -4,8 +4,11 @@ import com.velocitypowered.natives.compression.VelocityCompressor;
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.adventure.AdventureSerializer;
|
||||
import net.minestom.server.adventure.audience.PacketGroupingAudience;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||
import net.minestom.server.network.netty.packet.FramedPacket;
|
||||
@ -18,6 +21,7 @@ import net.minestom.server.utils.callback.validator.PlayerValidator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
@ -34,6 +38,39 @@ public final class PacketUtils {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to an audience. This method performs the following steps in the
|
||||
* following order:
|
||||
* <ol>
|
||||
* <li>If {@code audience} is a {@link Player}, send the packet to them.</li>
|
||||
* <li>Otherwise, if {@code audience} is a {@link PacketGroupingAudience}, call
|
||||
* {@link #sendGroupedPacket(Collection, ServerPacket)} on the players that the
|
||||
* grouping audience contains.</li>
|
||||
* <li>Otherwise, if {@code audience} is a {@link ForwardingAudience.Single},
|
||||
* call this method on the single audience inside the forwarding audience.</li>
|
||||
* <li>Otherwise, if {@code audience} is a {@link ForwardingAudience}, call this
|
||||
* method for each audience member of the forwarding audience.</li>
|
||||
* <li>Otherwise, do nothing.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param audience the audience
|
||||
* @param packet the packet
|
||||
*/
|
||||
@SuppressWarnings("OverrideOnly") // we need to access the audiences inside ForwardingAudience
|
||||
public static void sendPacket(@NotNull Audience audience, @NotNull ServerPacket packet) {
|
||||
if (audience instanceof Player) {
|
||||
((Player) audience).getPlayerConnection().sendPacket(packet);
|
||||
} else if (audience instanceof PacketGroupingAudience) {
|
||||
PacketUtils.sendGroupedPacket(((PacketGroupingAudience) audience).getPlayers(), packet);
|
||||
} else if (audience instanceof ForwardingAudience.Single) {
|
||||
PacketUtils.sendPacket(((ForwardingAudience.Single) audience).audience(), packet);
|
||||
} else if (audience instanceof ForwardingAudience) {
|
||||
for (Audience member : ((ForwardingAudience) audience).audiences()) {
|
||||
PacketUtils.sendPacket(member, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a {@link ServerPacket} to multiple players.
|
||||
* <p>
|
||||
|
@ -84,6 +84,20 @@ public final class ChunkUtils {
|
||||
return isLoaded(chunk);
|
||||
}
|
||||
|
||||
public static boolean same(@NotNull Chunk chunk, double x, double z) {
|
||||
final int chunkX = getChunkCoordinate(x);
|
||||
final int chunkZ = getChunkCoordinate(z);
|
||||
return chunk.getChunkX() == chunkX && chunk.getChunkZ() == chunkZ;
|
||||
}
|
||||
|
||||
public static boolean same(@NotNull Position pos1, @NotNull Position pos2) {
|
||||
final int x1 = getChunkCoordinate(pos1.getX());
|
||||
final int z1 = getChunkCoordinate(pos1.getZ());
|
||||
final int x2 = getChunkCoordinate(pos2.getX());
|
||||
final int z2 = getChunkCoordinate(pos2.getZ());
|
||||
return x1 == x2 && z1 == z2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param xz the instance coordinate to convert
|
||||
* @return the chunk X or Z based on the argument
|
||||
|
@ -22,8 +22,6 @@ public class Main {
|
||||
public static void main(String[] args) {
|
||||
MinecraftServer minecraftServer = MinecraftServer.init();
|
||||
|
||||
// MinecraftServer.setShouldProcessNettyErrors(true);
|
||||
|
||||
BlockManager blockManager = MinecraftServer.getBlockManager();
|
||||
blockManager.registerCustomBlock(new CustomBlockSample());
|
||||
blockManager.registerCustomBlock(new UpdatableBlockDemo());
|
||||
|
Loading…
Reference in New Issue
Block a user