mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-01 05:58:00 +01:00
Merge branch 'master' of https://github.com/Minestom/Minestom
Conflicts: src/main/java/net/minestom/server/MinecraftServer.java src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java
This commit is contained in:
commit
1798b50092
@ -9,9 +9,10 @@ import net.minestom.server.advancements.AdvancementManager;
|
||||
import net.minestom.server.benchmark.BenchmarkManager;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
import net.minestom.server.data.DataManager;
|
||||
import net.minestom.server.data.DataType;
|
||||
import net.minestom.server.data.SerializableData;
|
||||
import net.minestom.server.entity.EntityManager;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||
import net.minestom.server.fluids.Fluid;
|
||||
import net.minestom.server.gamedata.loottables.LootTableManager;
|
||||
@ -19,6 +20,8 @@ import net.minestom.server.gamedata.tags.TagManager;
|
||||
import net.minestom.server.instance.InstanceManager;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockManager;
|
||||
import net.minestom.server.instance.block.CustomBlock;
|
||||
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||
import net.minestom.server.item.Enchantment;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||
@ -81,10 +84,10 @@ public class MinecraftServer {
|
||||
public static final int CHUNK_VIEW_DISTANCE = 10;
|
||||
public static final int ENTITY_VIEW_DISTANCE = 5;
|
||||
public static final int COMPRESSION_THRESHOLD = 256;
|
||||
// Can be modified at performance cost when decreased
|
||||
// Can be modified at performance cost when increased
|
||||
public static final int TICK_PER_SECOND = 20;
|
||||
private static final int MS_TO_SEC = 1000;
|
||||
public static final int TICK_MS = MS_TO_SEC / 20;
|
||||
public static final int TICK_PER_SECOND = MS_TO_SEC / TICK_MS;
|
||||
public static final int TICK_MS = MS_TO_SEC / TICK_PER_SECOND;
|
||||
|
||||
@Getter @Setter
|
||||
private static boolean hardcoreLook = false;
|
||||
@ -95,7 +98,6 @@ public class MinecraftServer {
|
||||
private static boolean fixLighting = true;
|
||||
|
||||
//Rate Limiting
|
||||
@Getter @Setter
|
||||
private static int rateLimit = 0;
|
||||
|
||||
// Networking
|
||||
@ -217,80 +219,189 @@ public class MinecraftServer {
|
||||
PacketWriterUtils.writeAndSend(connectionManager.getOnlinePlayers(), brandMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the max number of packets a client can send over 1 second
|
||||
*
|
||||
* @return the packet count limit over 1 second
|
||||
*/
|
||||
public static int getRateLimit() {
|
||||
return rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the number of packet a client can send over 1 second without being disconnected
|
||||
*
|
||||
* @param rateLimit the number of packet, 0 to disable
|
||||
*/
|
||||
public static void setRateLimit(int rateLimit) {
|
||||
MinecraftServer.rateLimit = rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the server difficulty showed in game option
|
||||
*
|
||||
* @return the server difficulty
|
||||
*/
|
||||
public static Difficulty getDifficulty() {
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the server difficulty and send the appropriate packet to all connected clients
|
||||
*
|
||||
* @param difficulty the new server difficulty
|
||||
*/
|
||||
public static void setDifficulty(Difficulty difficulty) {
|
||||
MinecraftServer.difficulty = difficulty;
|
||||
for (Player player : connectionManager.getOnlinePlayers()) {
|
||||
ServerDifficultyPacket serverDifficultyPacket = new ServerDifficultyPacket();
|
||||
serverDifficultyPacket.difficulty = difficulty;
|
||||
serverDifficultyPacket.locked = true;
|
||||
player.getPlayerConnection().sendPacket(serverDifficultyPacket);
|
||||
}
|
||||
|
||||
// The difficulty packet
|
||||
ServerDifficultyPacket serverDifficultyPacket = new ServerDifficultyPacket();
|
||||
serverDifficultyPacket.difficulty = difficulty;
|
||||
serverDifficultyPacket.locked = true; // Can only be modified on singleplayer
|
||||
// Send the packet to all online players
|
||||
PacketWriterUtils.writeAndSend(connectionManager.getOnlinePlayers(), serverDifficultyPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling all incoming packets
|
||||
*
|
||||
* @return the packet listener manager
|
||||
*/
|
||||
public static PacketListenerManager getPacketListenerManager() {
|
||||
return packetListenerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the netty server
|
||||
*
|
||||
* @return the netty server
|
||||
*/
|
||||
public static NettyServer getNettyServer() {
|
||||
return nettyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling all registered instances
|
||||
*
|
||||
* @return the instance manager
|
||||
*/
|
||||
public static InstanceManager getInstanceManager() {
|
||||
return instanceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling {@link CustomBlock} and {@link BlockPlacementRule}
|
||||
*
|
||||
* @return the block manager
|
||||
*/
|
||||
public static BlockManager getBlockManager() {
|
||||
return blockManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling waiting players
|
||||
*
|
||||
* @return the entity manager
|
||||
*/
|
||||
public static EntityManager getEntityManager() {
|
||||
return entityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling commands
|
||||
*
|
||||
* @return the command manager
|
||||
*/
|
||||
public static CommandManager getCommandManager() {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling recipes show to the clients
|
||||
*
|
||||
* @return the recipe manager
|
||||
*/
|
||||
public static RecipeManager getRecipeManager() {
|
||||
return recipeManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling storage
|
||||
*
|
||||
* @return the storage manager
|
||||
*/
|
||||
public static StorageManager getStorageManager() {
|
||||
return storageManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling {@link DataType} used by {@link SerializableData}
|
||||
*
|
||||
* @return the data manager
|
||||
*/
|
||||
public static DataManager getDataManager() {
|
||||
return dataManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling teams
|
||||
*
|
||||
* @return the team manager
|
||||
*/
|
||||
public static TeamManager getTeamManager() {
|
||||
return teamManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling scheduled tasks
|
||||
*
|
||||
* @return the scheduler manager
|
||||
*/
|
||||
public static SchedulerManager getSchedulerManager() {
|
||||
return schedulerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling server monitoring
|
||||
*
|
||||
* @return the benchmark manager
|
||||
*/
|
||||
public static BenchmarkManager getBenchmarkManager() {
|
||||
return benchmarkManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling server connections
|
||||
*
|
||||
* @return the connection manager
|
||||
*/
|
||||
public static ConnectionManager getConnectionManager() {
|
||||
return connectionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the consumer executed to show server-list data
|
||||
*
|
||||
* @return the response data consumer
|
||||
*/
|
||||
public static ResponseDataConsumer getResponseDataConsumer() {
|
||||
return responseDataConsumer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling loot tables
|
||||
*
|
||||
* @return the loot table manager
|
||||
*/
|
||||
public static LootTableManager getLootTableManager() {
|
||||
return lootTableManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling dimensions
|
||||
*
|
||||
* @return the dimension manager
|
||||
*/
|
||||
public static DimensionTypeManager getDimensionTypeManager() {
|
||||
return dimensionTypeManager;
|
||||
}
|
||||
@ -299,18 +410,40 @@ public class MinecraftServer {
|
||||
return biomeManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling advancements
|
||||
*
|
||||
* @return the advancement manager
|
||||
*/
|
||||
public static AdvancementManager getAdvancementManager() {
|
||||
return advancementManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling tags
|
||||
*
|
||||
* @return the tag manager
|
||||
*/
|
||||
public static TagManager getTagManager() {
|
||||
return tagManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the manager handling the server ticks
|
||||
*
|
||||
* @return the update manager
|
||||
*/
|
||||
public static UpdateManager getUpdateManager() {
|
||||
return updateManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server
|
||||
*
|
||||
* @param address the server address
|
||||
* @param port the server port
|
||||
* @param responseDataConsumer the response data consumer, can be null
|
||||
*/
|
||||
public void start(String address, int port, ResponseDataConsumer responseDataConsumer) {
|
||||
LOGGER.info("Starting Minestom server.");
|
||||
MinecraftServer.responseDataConsumer = responseDataConsumer;
|
||||
@ -322,6 +455,12 @@ public class MinecraftServer {
|
||||
LOGGER.info("Minestom server started successfully.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server
|
||||
*
|
||||
* @param address the server address
|
||||
* @param port the server port
|
||||
*/
|
||||
public void start(String address, int port) {
|
||||
start(address, port, null);
|
||||
}
|
||||
|
@ -14,7 +14,10 @@ import net.minestom.server.event.entity.EntitySpawnEvent;
|
||||
import net.minestom.server.event.entity.EntityTickEvent;
|
||||
import net.minestom.server.event.entity.EntityVelocityEvent;
|
||||
import net.minestom.server.event.handler.EventHandler;
|
||||
import net.minestom.server.instance.*;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.InstanceManager;
|
||||
import net.minestom.server.instance.WorldBorder;
|
||||
import net.minestom.server.instance.block.CustomBlock;
|
||||
import net.minestom.server.network.packet.PacketWriter;
|
||||
import net.minestom.server.network.packet.server.play.*;
|
||||
@ -634,13 +637,11 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
|
||||
*
|
||||
* @param instance the new instance of the entity
|
||||
* @throws NullPointerException if {@code instance} is null
|
||||
* @throws IllegalStateException if {@code instance} has not been registered in
|
||||
* {@link InstanceManager#createInstanceContainer()} or
|
||||
* {@link InstanceManager#createSharedInstance(InstanceContainer)}
|
||||
* @throws IllegalStateException if {@code instance} has not been registered in {@link InstanceManager}
|
||||
*/
|
||||
public void setInstance(Instance instance) {
|
||||
Check.notNull(instance, "instance cannot be null!");
|
||||
Check.stateCondition(!MinecraftServer.getInstanceManager().getInstances().contains(instance),
|
||||
Check.stateCondition(!instance.isRegistered(),
|
||||
"Instances need to be registered with InstanceManager#createInstanceContainer or InstanceManager#createSharedInstance");
|
||||
|
||||
if (this.instance != null) {
|
||||
|
@ -602,6 +602,35 @@ public class Player extends LivingEntity implements CommandSender {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a plugin message to the player
|
||||
*
|
||||
* @param channel the message channel
|
||||
* @param data the message data
|
||||
*/
|
||||
public void sendPluginMessage(String channel, byte[] data) {
|
||||
PluginMessagePacket pluginMessagePacket = new PluginMessagePacket();
|
||||
pluginMessagePacket.channel = channel;
|
||||
pluginMessagePacket.data = data;
|
||||
playerConnection.sendPacket(pluginMessagePacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a plugin message to the player
|
||||
*
|
||||
* @param channel the message channel
|
||||
* @param message the message
|
||||
*/
|
||||
public void sendPluginMessage(String channel, String message) {
|
||||
// Write the data
|
||||
PacketWriter writer = new PacketWriter();
|
||||
writer.writeSizedString(message);
|
||||
// Retrieve the data
|
||||
final byte[] data = writer.toByteArray();
|
||||
|
||||
sendPluginMessage(channel, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a {@link BlockBreakAnimationPacket} packet to the player and his viewers
|
||||
* Setting {@code destroyStage} to -1 resets the break animation
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.network.PacketWriterUtils;
|
||||
import net.minestom.server.network.packet.server.play.ExplosionPacket;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
|
||||
@ -78,9 +79,8 @@ public abstract class Explosion {
|
||||
|
||||
postExplosion(instance, blocks, packet);
|
||||
|
||||
instance.getPlayers().forEach(player -> {
|
||||
player.sendPacketToViewersAndSelf(packet);
|
||||
});
|
||||
// TODO send only to close players
|
||||
PacketWriterUtils.writeAndSend(instance.getPlayers(), packet);
|
||||
|
||||
postSend(instance, blocks);
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ public interface ExplosionSupplier {
|
||||
/**
|
||||
* Creates a new explosion
|
||||
*
|
||||
* @param centerX center of the explosion
|
||||
* @param centerY center of the explosion
|
||||
* @param centerZ center of the explosion
|
||||
* @param centerX center X of the explosion
|
||||
* @param centerY center Y of the explosion
|
||||
* @param centerZ center Z of the explosion
|
||||
* @param strength strength of the explosion
|
||||
* @param additionalData data passed via {@link Instance#explode)}. Can be null
|
||||
* @return Explosion object representing the algorithm to use
|
||||
|
@ -49,6 +49,8 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||
protected static final UpdateManager UPDATE_MANAGER = MinecraftServer.getUpdateManager();
|
||||
|
||||
private boolean registered;
|
||||
|
||||
private DimensionType dimensionType;
|
||||
|
||||
private WorldBorder worldBorder;
|
||||
@ -306,6 +308,26 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Get if the instance has been registered in {@link InstanceManager}
|
||||
*
|
||||
* @return true if the instance has been registered
|
||||
*/
|
||||
public boolean isRegistered() {
|
||||
return registered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the registered field
|
||||
* <p>
|
||||
* WARNING: should only be used by {@link InstanceManager}
|
||||
*
|
||||
* @param registered true to mark the instance as registered
|
||||
*/
|
||||
protected void setRegistered(boolean registered) {
|
||||
this.registered = registered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instance dimension
|
||||
*
|
||||
|
@ -527,6 +527,13 @@ public class InstanceContainer extends Instance {
|
||||
return position.getY() < -64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a {@link SharedInstance} to this container
|
||||
* <p>
|
||||
* Only used by {@link InstanceManager}
|
||||
*
|
||||
* @param sharedInstance the shared instance to assign to this container
|
||||
*/
|
||||
protected void addSharedInstance(SharedInstance sharedInstance) {
|
||||
this.sharedInstances.add(sharedInstance);
|
||||
}
|
||||
|
@ -5,54 +5,119 @@ import net.minestom.server.utils.validate.Check;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Used to register instances
|
||||
*/
|
||||
public final class InstanceManager {
|
||||
|
||||
private Set<Instance> instances = Collections.synchronizedSet(new HashSet<>());
|
||||
private final Set<Instance> instances = new CopyOnWriteArraySet<>();
|
||||
|
||||
public InstanceContainer createInstanceContainer(InstanceContainer instanceContainer) {
|
||||
this.instances.add(instanceContainer);
|
||||
/**
|
||||
* Register an {@link InstanceContainer}
|
||||
*
|
||||
* @param instanceContainer the instance to register
|
||||
* @return the registered {@link InstanceContainer}
|
||||
*/
|
||||
public InstanceContainer registerInstanceContainer(InstanceContainer instanceContainer) {
|
||||
registerInstance(instanceContainer);
|
||||
return instanceContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register an {@link InstanceContainer} with the specified dimension and storage folder
|
||||
*
|
||||
* @param dimensionType the dimension of the instance
|
||||
* @param storageFolder the storage folder of the instance, can be null
|
||||
* @return the created {@link InstanceContainer}
|
||||
*/
|
||||
public InstanceContainer createInstanceContainer(DimensionType dimensionType, StorageFolder storageFolder) {
|
||||
InstanceContainer instance = new InstanceContainer(UUID.randomUUID(), dimensionType, storageFolder);
|
||||
return createInstanceContainer(instance);
|
||||
final InstanceContainer instance = new InstanceContainer(UUID.randomUUID(), dimensionType, storageFolder);
|
||||
return registerInstanceContainer(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register an {@link InstanceContainer} with the specified storage folder
|
||||
*
|
||||
* @param storageFolder the storage folder of the instance, can be null
|
||||
* @return the created {@link InstanceContainer}
|
||||
*/
|
||||
public InstanceContainer createInstanceContainer(StorageFolder storageFolder) {
|
||||
return createInstanceContainer(DimensionType.OVERWORLD, storageFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register an {@link InstanceContainer} with the specified dimension
|
||||
*
|
||||
* @param dimensionType the dimension of the instance
|
||||
* @return the created {@link InstanceContainer}
|
||||
*/
|
||||
public InstanceContainer createInstanceContainer(DimensionType dimensionType) {
|
||||
return createInstanceContainer(dimensionType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register an {@link InstanceContainer}
|
||||
*
|
||||
* @return the created {@link InstanceContainer}
|
||||
*/
|
||||
public InstanceContainer createInstanceContainer() {
|
||||
return createInstanceContainer(DimensionType.OVERWORLD);
|
||||
}
|
||||
|
||||
public SharedInstance createSharedInstance(SharedInstance sharedInstance) {
|
||||
/**
|
||||
* Register a {@link SharedInstance}
|
||||
* <p>
|
||||
* WARNING: the shared instance needs to have an {@link InstanceContainer} assigned to it
|
||||
*
|
||||
* @param sharedInstance the instance to register
|
||||
* @return the registered {@link SharedInstance}
|
||||
* @throws NullPointerException if the shared instance doesn't have an {@link InstanceContainer} assigned to it
|
||||
*/
|
||||
public SharedInstance registerSharedInstance(SharedInstance sharedInstance) {
|
||||
final InstanceContainer instanceContainer = sharedInstance.getInstanceContainer();
|
||||
Check.notNull(instanceContainer, "SharedInstance needs to have an InstanceContainer to be created!");
|
||||
|
||||
instanceContainer.addSharedInstance(sharedInstance);
|
||||
this.instances.add(sharedInstance);
|
||||
registerInstance(sharedInstance);
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register a {@link SharedInstance}
|
||||
*
|
||||
* @param instanceContainer the container assigned to the shared instance
|
||||
* @return the created {@link SharedInstance}
|
||||
* @throws IllegalStateException if {@code instanceContainer} is not registered
|
||||
*/
|
||||
public SharedInstance createSharedInstance(InstanceContainer instanceContainer) {
|
||||
Check.notNull(instanceContainer, "Instance container cannot be null when creating a SharedInstance!");
|
||||
Check.stateCondition(!instanceContainer.isRegistered(), "The container needs to be register in the InstanceManager");
|
||||
|
||||
final SharedInstance sharedInstance = new SharedInstance(UUID.randomUUID(), instanceContainer);
|
||||
return createSharedInstance(sharedInstance);
|
||||
return registerSharedInstance(sharedInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the registered instances
|
||||
*
|
||||
* @return an unmodifiable set containing all the registered instances
|
||||
*/
|
||||
public Set<Instance> getInstances() {
|
||||
return Collections.unmodifiableSet(instances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the instance internally
|
||||
*
|
||||
* @param instance the instance to register
|
||||
*/
|
||||
private void registerInstance(Instance instance) {
|
||||
instance.setRegistered(true);
|
||||
this.instances.add(instance);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,10 +28,11 @@ public class MinestomBasicChunkLoader implements IChunkLoader {
|
||||
final int chunkZ = chunk.getChunkZ();
|
||||
|
||||
try {
|
||||
final String key = getChunkKey(chunkX, chunkZ);
|
||||
final byte[] data = chunk.getSerializedData();
|
||||
if (data == null)
|
||||
return;
|
||||
storageFolder.set(getChunkKey(chunkX, chunkZ), data);
|
||||
storageFolder.set(key, data);
|
||||
|
||||
if (callback != null)
|
||||
callback.run();
|
||||
@ -53,6 +54,13 @@ public class MinestomBasicChunkLoader implements IChunkLoader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chunk key used by the {@link StorageFolder}
|
||||
*
|
||||
* @param chunkX the chunk X
|
||||
* @param chunkZ the chunk Z
|
||||
* @return the chunk key
|
||||
*/
|
||||
private static String getChunkKey(int chunkX, int chunkZ) {
|
||||
return chunkX + "." + chunkZ;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package net.minestom.server.instance;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.PacketWriterUtils;
|
||||
import net.minestom.server.network.packet.server.play.WorldBorderPacket;
|
||||
import net.minestom.server.utils.Position;
|
||||
|
||||
@ -59,6 +60,11 @@ public class WorldBorder {
|
||||
return centerX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the center X of the world border
|
||||
*
|
||||
* @param centerX the new center X
|
||||
*/
|
||||
public void setCenterX(float centerX) {
|
||||
this.centerX = centerX;
|
||||
refreshCenter();
|
||||
@ -73,6 +79,11 @@ public class WorldBorder {
|
||||
return centerZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the center Z of the world border
|
||||
*
|
||||
* @param centerZ the new center Z
|
||||
*/
|
||||
public void setCenterZ(float centerZ) {
|
||||
this.centerZ = centerZ;
|
||||
refreshCenter();
|
||||
@ -220,6 +231,11 @@ public class WorldBorder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the world border init packet to a player
|
||||
*
|
||||
* @param player the player to send the packet to
|
||||
*/
|
||||
protected void init(Player player) {
|
||||
WorldBorderPacket worldBorderPacket = new WorldBorderPacket();
|
||||
worldBorderPacket.action = WorldBorderPacket.Action.INITIALIZE;
|
||||
@ -237,6 +253,9 @@ public class WorldBorder {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the new world border centers to all instance players
|
||||
*/
|
||||
private void refreshCenter() {
|
||||
WorldBorderPacket worldBorderPacket = new WorldBorderPacket();
|
||||
worldBorderPacket.action = WorldBorderPacket.Action.SET_CENTER;
|
||||
@ -244,8 +263,13 @@ public class WorldBorder {
|
||||
sendPacket(worldBorderPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a {@link WorldBorderPacket} to all the instance players
|
||||
*
|
||||
* @param worldBorderPacket the packet to send
|
||||
*/
|
||||
private void sendPacket(WorldBorderPacket worldBorderPacket) {
|
||||
instance.getPlayers().forEach(player -> player.getPlayerConnection().sendPacket(worldBorderPacket));
|
||||
PacketWriterUtils.writeAndSend(instance.getPlayers(), worldBorderPacket);
|
||||
}
|
||||
|
||||
public enum CollisionAxis {
|
||||
|
@ -13,19 +13,34 @@ import java.util.Collection;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class PacketWriterUtils {
|
||||
/**
|
||||
* Utils class used to write packets in the appropriate thread pool
|
||||
*/
|
||||
public final class PacketWriterUtils {
|
||||
|
||||
private static ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_PACKET_WRITER, MinecraftServer.THREAD_NAME_PACKET_WRITER);
|
||||
private static final ExecutorService PACKET_WRITER_POOL = new MinestomThread(MinecraftServer.THREAD_COUNT_PACKET_WRITER, MinecraftServer.THREAD_NAME_PACKET_WRITER);
|
||||
|
||||
/**
|
||||
* Write the packet in the writer thread pool
|
||||
*
|
||||
* @param serverPacket the packet to write
|
||||
* @param consumer the consumer called once the packet has been written
|
||||
*/
|
||||
public static void writeCallbackPacket(ServerPacket serverPacket, Consumer<ByteBuf> consumer) {
|
||||
batchesPool.execute(() -> {
|
||||
PACKET_WRITER_POOL.execute(() -> {
|
||||
final ByteBuf buffer = PacketUtils.writePacket(serverPacket);
|
||||
consumer.accept(buffer);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a packet in the writer thread pool and send it to every players in {@code players}
|
||||
*
|
||||
* @param players the players list to send the packet to
|
||||
* @param serverPacket the packet to write and send
|
||||
*/
|
||||
public static void writeAndSend(Collection<Player> players, ServerPacket serverPacket) {
|
||||
batchesPool.execute(() -> {
|
||||
PACKET_WRITER_POOL.execute(() -> {
|
||||
if (players.isEmpty())
|
||||
return;
|
||||
|
||||
@ -42,14 +57,27 @@ public class PacketWriterUtils {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a packet and send it to a player connection
|
||||
*
|
||||
* @param playerConnection the connection to send the packet to
|
||||
* @param serverPacket the packet to write and send
|
||||
*/
|
||||
public static void writeAndSend(PlayerConnection playerConnection, ServerPacket serverPacket) {
|
||||
batchesPool.execute(() -> {
|
||||
PACKET_WRITER_POOL.execute(() -> {
|
||||
playerConnection.sendPacket(serverPacket);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a packet and send it to a player
|
||||
*
|
||||
* @param player the player to send the packet to
|
||||
* @param serverPacket the packet to write and send
|
||||
*/
|
||||
public static void writeAndSend(Player player, ServerPacket serverPacket) {
|
||||
writeAndSend(player.getPlayerConnection(), serverPacket);
|
||||
final PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
writeAndSend(playerConnection, serverPacket);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class ClientChannel extends SimpleChannelInboundHandler<InboundPacket> {
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) {
|
||||
System.out.println("CONNECTION");
|
||||
//System.out.println("CONNECTION");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -28,7 +28,7 @@ public class ClientChannel extends SimpleChannelInboundHandler<InboundPacket> {
|
||||
try {
|
||||
packetProcessor.process(ctx, packet);
|
||||
} finally {
|
||||
int availableBytes = packet.body.readableBytes();
|
||||
final int availableBytes = packet.body.readableBytes();
|
||||
|
||||
if (availableBytes > 0) {
|
||||
// TODO log4j2
|
||||
@ -44,6 +44,7 @@ public class ClientChannel extends SimpleChannelInboundHandler<InboundPacket> {
|
||||
public void channelInactive(ChannelHandlerContext ctx) {
|
||||
PlayerConnection playerConnection = packetProcessor.getPlayerConnection(ctx);
|
||||
if (playerConnection != null) {
|
||||
// Remove the connection
|
||||
playerConnection.refreshOnline(false);
|
||||
Player player = playerConnection.getPlayer();
|
||||
if (player != null) {
|
||||
|
@ -2,11 +2,11 @@ package net.minestom.server.network.player;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import lombok.Getter;
|
||||
import net.minestom.server.extras.mojangAuth.Decrypter;
|
||||
import net.minestom.server.extras.mojangAuth.Encrypter;
|
||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import net.minestom.server.network.netty.codec.PacketCompressor;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.login.SetCompressionPacket;
|
||||
@ -20,79 +20,76 @@ import java.net.SocketAddress;
|
||||
*/
|
||||
public class NettyPlayerConnection extends PlayerConnection {
|
||||
|
||||
private final SocketChannel channel;
|
||||
@Getter
|
||||
private boolean encrypted = false;
|
||||
@Getter
|
||||
private boolean compressed = false;
|
||||
private final SocketChannel channel;
|
||||
@Getter
|
||||
private boolean encrypted = false;
|
||||
@Getter
|
||||
private boolean compressed = false;
|
||||
|
||||
public NettyPlayerConnection(SocketChannel channel) {
|
||||
super();
|
||||
this.channel = channel;
|
||||
}
|
||||
public NettyPlayerConnection(SocketChannel channel) {
|
||||
super();
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public void setEncryptionKey(SecretKey secretKey) {
|
||||
this.encrypted = true;
|
||||
getChannel().pipeline().addBefore("framer", "decrypt", new Decrypter(MojangCrypt.getCipher(2, secretKey)));
|
||||
getChannel().pipeline().addBefore("framer", "encrypt", new Encrypter(MojangCrypt.getCipher(1, secretKey)));
|
||||
}
|
||||
public void setEncryptionKey(SecretKey secretKey) {
|
||||
this.encrypted = true;
|
||||
getChannel().pipeline().addBefore("framer", "decrypt", new Decrypter(MojangCrypt.getCipher(2, secretKey)));
|
||||
getChannel().pipeline().addBefore("framer", "encrypt", new Encrypter(MojangCrypt.getCipher(1, secretKey)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void enableCompression(int threshold) {
|
||||
this.compressed = true;
|
||||
this.compressed = true;
|
||||
sendPacket(new SetCompressionPacket(threshold));
|
||||
channel.pipeline().addAfter("framer", "compressor", new PacketCompressor(threshold));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(ByteBuf buffer, boolean copy) {
|
||||
//System.out.println(getConnectionState() + " out");
|
||||
if ((encrypted || compressed) && copy) {
|
||||
buffer = buffer.copy();
|
||||
buffer.retain();
|
||||
channel.writeAndFlush(buffer);
|
||||
buffer.release();
|
||||
} else {
|
||||
getChannel().writeAndFlush(buffer);
|
||||
}
|
||||
}
|
||||
public void sendPacket(ByteBuf buffer, boolean copy) {
|
||||
if ((encrypted || compressed) && copy) {
|
||||
buffer = buffer.copy();
|
||||
buffer.retain();
|
||||
channel.writeAndFlush(buffer);
|
||||
buffer.release();
|
||||
} else {
|
||||
getChannel().writeAndFlush(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(ByteBuf buffer, boolean copy) {
|
||||
//System.out.println(getConnectionState() + " out");
|
||||
if ((encrypted || compressed) && copy) {
|
||||
buffer = buffer.copy();
|
||||
buffer.retain();
|
||||
channel.write(buffer);
|
||||
buffer.release();
|
||||
} else {
|
||||
getChannel().write(buffer);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void writePacket(ByteBuf buffer, boolean copy) {
|
||||
if ((encrypted || compressed) && copy) {
|
||||
buffer = buffer.copy();
|
||||
buffer.retain();
|
||||
channel.write(buffer);
|
||||
buffer.release();
|
||||
} else {
|
||||
getChannel().write(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(ServerPacket serverPacket) {
|
||||
//System.out.println(serverPacket.getClass().getName() + " out");
|
||||
@Override
|
||||
public void sendPacket(ServerPacket serverPacket) {
|
||||
channel.writeAndFlush(serverPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
getChannel().flush();
|
||||
}
|
||||
@Override
|
||||
public void flush() {
|
||||
getChannel().flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getRemoteAddress() {
|
||||
return getChannel().remoteAddress();
|
||||
}
|
||||
@Override
|
||||
public SocketAddress getRemoteAddress() {
|
||||
return getChannel().remoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
getChannel().close();
|
||||
}
|
||||
@Override
|
||||
public void disconnect() {
|
||||
getChannel().close();
|
||||
}
|
||||
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.chat.ChatColor;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
@ -32,11 +33,13 @@ public abstract class PlayerConnection {
|
||||
private ConnectionState connectionState;
|
||||
private boolean online;
|
||||
|
||||
private static final ColoredText rateLimitKickMessage = ColoredText.of("Too Many Packets");
|
||||
// Text used to kick client sending too many packets
|
||||
private static final ColoredText rateLimitKickMessage = ColoredText.of(ChatColor.RED + "Too Many Packets");
|
||||
|
||||
//Connection Stats
|
||||
@Getter
|
||||
private final AtomicInteger packetCounter = new AtomicInteger(0);
|
||||
private final AtomicInteger lastPacketCounter = new AtomicInteger(0);
|
||||
private short tickCounter = 0;
|
||||
|
||||
public PlayerConnection() {
|
||||
@ -44,14 +47,21 @@ public abstract class PlayerConnection {
|
||||
this.connectionState = ConnectionState.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update values related to the network connection
|
||||
*/
|
||||
public void updateStats() {
|
||||
// Check rate limit
|
||||
if (MinecraftServer.getRateLimit() > 0) {
|
||||
tickCounter++;
|
||||
if (tickCounter % 20 == 0 && tickCounter > 0) {
|
||||
if (tickCounter % MinecraftServer.TICK_PER_SECOND == 0 && tickCounter > 0) {
|
||||
tickCounter = 0;
|
||||
// Retrieve the packet count
|
||||
final int count = packetCounter.get();
|
||||
packetCounter.set(0);
|
||||
this.lastPacketCounter.set(count);
|
||||
this.packetCounter.set(0);
|
||||
if (count > MinecraftServer.getRateLimit()) {
|
||||
// Sent too many packets
|
||||
if (connectionState == ConnectionState.LOGIN) {
|
||||
sendPacket(new LoginDisconnect("Too Many Packets"));
|
||||
} else {
|
||||
@ -96,6 +106,11 @@ public abstract class PlayerConnection {
|
||||
*/
|
||||
public abstract void flush();
|
||||
|
||||
/**
|
||||
* Get the remote address of the client
|
||||
*
|
||||
* @return the remote address
|
||||
*/
|
||||
public abstract SocketAddress getRemoteAddress();
|
||||
|
||||
/**
|
||||
@ -140,7 +155,21 @@ public abstract class PlayerConnection {
|
||||
this.connectionState = connectionState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client connection state
|
||||
*
|
||||
* @return the client connection state
|
||||
*/
|
||||
public ConnectionState getConnectionState() {
|
||||
return connectionState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of packet the client sent over the last second
|
||||
*
|
||||
* @return the number of packet sent over the last second
|
||||
*/
|
||||
public int getLastPacketCounter() {
|
||||
return lastPacketCounter.get();
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,21 @@ import io.netty.buffer.Unpooled;
|
||||
import net.minestom.server.network.packet.PacketWriter;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
|
||||
/**
|
||||
* Class used to write packets
|
||||
*/
|
||||
public final class PacketUtils {
|
||||
|
||||
private PacketUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a {@link ServerPacket} into a {@link ByteBuf}
|
||||
*
|
||||
* @param buf the recipient of {@code packet}
|
||||
* @param packet the packet to write into {@code buf}
|
||||
*/
|
||||
public static void writePacket(ByteBuf buf, ServerPacket packet) {
|
||||
PacketWriter writer = new PacketWriter();
|
||||
|
||||
@ -19,6 +28,12 @@ public final class PacketUtils {
|
||||
buf.writeBytes(writer.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a {@link ServerPacket} into a newly created {@link ByteBuf}
|
||||
*
|
||||
* @param packet the packet to write
|
||||
* @return a {@link ByteBuf} containing {@code packet}
|
||||
*/
|
||||
public static ByteBuf writePacket(ServerPacket packet) {
|
||||
ByteBuf buffer = Unpooled.buffer();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user